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()
305 if (game.envelope_active)
312 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
313 // SetDrawBackgroundMask(REDRAW_FIELD); // !!! 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)
716 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
718 redraw_mask = REDRAW_NONE;
721 if (redraw_mask & REDRAW_FIELD)
724 printf("::: REDRAW_FIELD\n");
727 if (game_status != GAME_MODE_PLAYING ||
728 redraw_mask & REDRAW_FROM_BACKBUFFER)
730 BlitBitmap(backbuffer, window,
731 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
736 BlitScreenToBitmap_RND(window);
738 int fx = FX, fy = FY;
741 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
742 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
743 int dx_var = dx * TILESIZE_VAR / TILESIZE;
744 int dy_var = dy * TILESIZE_VAR / TILESIZE;
747 // fx += dx * TILESIZE_VAR / TILESIZE;
748 // fy += dy * TILESIZE_VAR / TILESIZE;
750 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
751 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
754 /* !!! THIS WORKS !!! */
756 printf("::: %d, %d\n", scroll_x, scroll_y);
758 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
759 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
761 if (EVEN(SCR_FIELDX))
763 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
764 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
766 fx += (dx > 0 ? TILEX_VAR : 0);
773 if (EVEN(SCR_FIELDY))
775 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
776 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
778 fy += (dy > 0 ? TILEY_VAR : 0);
785 if (border.draw_masked[GAME_MODE_PLAYING])
787 if (buffer != backbuffer)
789 /* copy playfield buffer to backbuffer to add masked border */
790 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
791 DrawMaskedBorder(REDRAW_FIELD);
794 BlitBitmap(backbuffer, window,
795 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
800 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
806 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
808 (setup.soft_scrolling ?
809 "setup.soft_scrolling" :
810 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
811 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
812 ABS(ScreenGfxPos) == ScrollStepSize ?
813 "ABS(ScreenGfxPos) == ScrollStepSize" :
814 "redraw_tiles > REDRAWTILES_THRESHOLD"));
819 redraw_mask &= ~REDRAW_MAIN;
822 if (redraw_mask & REDRAW_DOORS)
824 if (redraw_mask & REDRAW_DOOR_1)
825 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
827 if (redraw_mask & REDRAW_DOOR_2)
828 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
830 if (redraw_mask & REDRAW_DOOR_3)
831 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
833 redraw_mask &= ~REDRAW_DOORS;
836 if (redraw_mask & REDRAW_MICROLEVEL)
838 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
839 SX, SY + 10 * TILEY);
841 redraw_mask &= ~REDRAW_MICROLEVEL;
844 if (redraw_mask & REDRAW_TILES)
847 printf("::: REDRAW_TILES\n");
853 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
856 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
857 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
860 int dx_var = dx * TILESIZE_VAR / TILESIZE;
861 int dy_var = dy * TILESIZE_VAR / TILESIZE;
863 int fx = FX, fy = FY;
865 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
866 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
868 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
869 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
871 if (EVEN(SCR_FIELDX))
873 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
875 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
884 fx += (dx_var > 0 ? TILEX_VAR : 0);
888 if (EVEN(SCR_FIELDY))
890 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
892 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
901 fy += (dy_var > 0 ? TILEY_VAR : 0);
906 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
909 for (x = 0; x < scr_fieldx; x++)
910 for (y = 0 ; y < scr_fieldy; y++)
911 if (redraw[redraw_x1 + x][redraw_y1 + y])
912 BlitBitmap(buffer, window,
913 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
914 TILEX_VAR, TILEY_VAR,
915 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
918 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
920 for (x = 0; x < SCR_FIELDX; x++)
921 for (y = 0 ; y < SCR_FIELDY; y++)
922 if (redraw[redraw_x1 + x][redraw_y1 + y])
923 BlitBitmap(buffer, window,
924 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
925 TILEX_VAR, TILEY_VAR,
926 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
930 for (x = 0; x < SCR_FIELDX; x++)
931 for (y = 0 ; y < SCR_FIELDY; y++)
932 if (redraw[redraw_x1 + x][redraw_y1 + y])
933 BlitBitmap(buffer, window,
934 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
935 SX + x * TILEX, SY + y * TILEY);
939 if (redraw_mask & REDRAW_FPS) /* display frames per second */
944 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
945 if (!global.fps_slowdown)
948 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
950 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
952 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
958 for (x = 0; x < MAX_BUF_XSIZE; x++)
959 for (y = 0; y < MAX_BUF_YSIZE; y++)
962 redraw_mask = REDRAW_NONE;
965 static void FadeCrossSaveBackbuffer()
967 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
970 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
972 static int fade_type_skip = FADE_TYPE_NONE;
973 void (*draw_border_function)(void) = NULL;
974 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
975 int x, y, width, height;
976 int fade_delay, post_delay;
978 if (fade_type == FADE_TYPE_FADE_OUT)
980 if (fade_type_skip != FADE_TYPE_NONE)
983 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
986 /* skip all fade operations until specified fade operation */
987 if (fade_type & fade_type_skip)
988 fade_type_skip = FADE_TYPE_NONE;
993 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
995 FadeCrossSaveBackbuffer();
1001 redraw_mask |= fade_mask;
1003 if (fade_type == FADE_TYPE_SKIP)
1006 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
1009 fade_type_skip = fade_mode;
1015 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1020 fade_delay = fading.fade_delay;
1021 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1024 if (fade_type_skip != FADE_TYPE_NONE)
1027 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1030 /* skip all fade operations until specified fade operation */
1031 if (fade_type & fade_type_skip)
1032 fade_type_skip = FADE_TYPE_NONE;
1042 if (global.autoplay_leveldir)
1044 // fading.fade_mode = FADE_MODE_NONE;
1051 if (fading.fade_mode == FADE_MODE_NONE)
1059 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1062 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1066 if (fade_mask == REDRAW_NONE)
1067 fade_mask = REDRAW_FIELD;
1070 // if (fade_mask & REDRAW_FIELD)
1071 if (fade_mask == REDRAW_FIELD)
1075 width = FULL_SXSIZE;
1076 height = FULL_SYSIZE;
1079 fade_delay = fading.fade_delay;
1080 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1083 if (border.draw_masked_when_fading)
1084 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
1086 DrawMaskedBorder_FIELD(); /* draw once */
1088 else /* REDRAW_ALL */
1096 fade_delay = fading.fade_delay;
1097 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1102 if (!setup.fade_screens ||
1104 fading.fade_mode == FADE_MODE_NONE)
1106 if (!setup.fade_screens || fade_delay == 0)
1109 if (fade_mode == FADE_MODE_FADE_OUT)
1113 if (fade_mode == FADE_MODE_FADE_OUT &&
1114 fading.fade_mode != FADE_MODE_NONE)
1115 ClearRectangle(backbuffer, x, y, width, height);
1121 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1123 redraw_mask &= ~fade_mask;
1125 /* always redraw area that was explicitly marked to fade */
1126 redraw_mask |= fade_mask;
1134 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1135 redraw_mask = REDRAW_NONE;
1136 // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1145 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1146 draw_border_function);
1148 redraw_mask &= ~fade_mask;
1151 void FadeIn(int fade_mask)
1153 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1154 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1156 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1159 void FadeOut(int fade_mask)
1161 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1162 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1164 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1166 global.border_status = game_status;
1169 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1171 static struct TitleFadingInfo fading_leave_stored;
1174 fading_leave_stored = fading_leave;
1176 fading = fading_leave_stored;
1179 void FadeSetEnterMenu()
1181 fading = menu.enter_menu;
1184 printf("::: storing enter_menu\n");
1187 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1190 void FadeSetLeaveMenu()
1192 fading = menu.leave_menu;
1195 printf("::: storing leave_menu\n");
1198 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1201 void FadeSetEnterScreen()
1203 fading = menu.enter_screen[game_status];
1206 printf("::: storing leave_screen[%d]\n", game_status);
1209 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1212 void FadeSetNextScreen()
1214 fading = menu.next_screen;
1217 printf("::: storing next_screen\n");
1220 // (do not overwrite fade mode set by FadeSetEnterScreen)
1221 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1224 void FadeSetLeaveScreen()
1227 printf("::: recalling last stored value\n");
1230 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1233 void FadeSetFromType(int type)
1235 if (type & TYPE_ENTER_SCREEN)
1236 FadeSetEnterScreen();
1237 else if (type & TYPE_ENTER)
1239 else if (type & TYPE_LEAVE)
1243 void FadeSetDisabled()
1245 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1247 fading = fading_none;
1250 void FadeSkipNextFadeIn()
1252 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1255 void FadeSkipNextFadeOut()
1257 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1260 void SetWindowBackgroundImageIfDefined(int graphic)
1262 if (graphic_info[graphic].bitmap)
1263 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1266 void SetMainBackgroundImageIfDefined(int graphic)
1268 if (graphic_info[graphic].bitmap)
1269 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1272 void SetDoorBackgroundImageIfDefined(int graphic)
1274 if (graphic_info[graphic].bitmap)
1275 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1278 void SetWindowBackgroundImage(int graphic)
1280 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1281 graphic_info[graphic].bitmap ?
1282 graphic_info[graphic].bitmap :
1283 graphic_info[IMG_BACKGROUND].bitmap);
1286 void SetMainBackgroundImage(int graphic)
1288 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1289 graphic_info[graphic].bitmap ?
1290 graphic_info[graphic].bitmap :
1291 graphic_info[IMG_BACKGROUND].bitmap);
1294 void SetDoorBackgroundImage(int graphic)
1296 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1297 graphic_info[graphic].bitmap ?
1298 graphic_info[graphic].bitmap :
1299 graphic_info[IMG_BACKGROUND].bitmap);
1302 void SetPanelBackground()
1305 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1308 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1309 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1311 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1312 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1313 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1314 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1317 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1318 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1321 SetDoorBackgroundBitmap(bitmap_db_panel);
1324 void DrawBackground(int x, int y, int width, int height)
1326 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1327 /* (when entering hall of fame after playing) */
1329 ClearRectangleOnBackground(drawto, x, y, width, height);
1331 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1337 if (IN_GFX_FIELD_FULL(x, y))
1338 redraw_mask |= REDRAW_FIELD;
1339 else if (IN_GFX_DOOR_1(x, y))
1340 redraw_mask |= REDRAW_DOOR_1;
1341 else if (IN_GFX_DOOR_2(x, y))
1342 redraw_mask |= REDRAW_DOOR_2;
1343 else if (IN_GFX_DOOR_3(x, y))
1344 redraw_mask |= REDRAW_DOOR_3;
1346 /* (this only works for the current arrangement of playfield and panels) */
1348 redraw_mask |= REDRAW_FIELD;
1349 else if (y < gfx.vy)
1350 redraw_mask |= REDRAW_DOOR_1;
1352 redraw_mask |= REDRAW_DOOR_2;
1356 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1357 redraw_mask |= REDRAW_FIELD;
1361 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1363 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1365 if (font->bitmap == NULL)
1368 DrawBackground(x, y, width, height);
1371 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1373 struct GraphicInfo *g = &graphic_info[graphic];
1375 if (g->bitmap == NULL)
1378 DrawBackground(x, y, width, height);
1383 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1384 /* (when entering hall of fame after playing) */
1385 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1387 /* !!! maybe this should be done before clearing the background !!! */
1388 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1390 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1391 SetDrawtoField(DRAW_BUFFERED);
1394 SetDrawtoField(DRAW_BACKBUFFER);
1397 void MarkTileDirty(int x, int y)
1399 int xx = redraw_x1 + x;
1400 int yy = redraw_y1 + y;
1402 if (!redraw[xx][yy])
1405 redraw[xx][yy] = TRUE;
1406 redraw_mask |= REDRAW_TILES;
1409 void SetBorderElement()
1413 BorderElement = EL_EMPTY;
1415 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1417 for (x = 0; x < lev_fieldx; x++)
1419 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1420 BorderElement = EL_STEELWALL;
1422 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1428 void FloodFillLevel(int from_x, int from_y, int fill_element,
1429 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1430 int max_fieldx, int max_fieldy)
1434 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1435 static int safety = 0;
1437 /* check if starting field still has the desired content */
1438 if (field[from_x][from_y] == fill_element)
1443 if (safety > max_fieldx * max_fieldy)
1444 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1446 old_element = field[from_x][from_y];
1447 field[from_x][from_y] = fill_element;
1449 for (i = 0; i < 4; i++)
1451 x = from_x + check[i][0];
1452 y = from_y + check[i][1];
1454 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1455 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1461 void SetRandomAnimationValue(int x, int y)
1463 gfx.anim_random_frame = GfxRandom[x][y];
1466 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1468 /* animation synchronized with global frame counter, not move position */
1469 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1470 sync_frame = FrameCounter;
1472 return getAnimationFrame(graphic_info[graphic].anim_frames,
1473 graphic_info[graphic].anim_delay,
1474 graphic_info[graphic].anim_mode,
1475 graphic_info[graphic].anim_start_frame,
1479 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1480 Bitmap **bitmap, int *x, int *y,
1481 boolean get_backside)
1485 int width_mult, width_div;
1486 int height_mult, height_div;
1490 { 15, 16, 2, 3 }, /* 1 x 1 */
1491 { 7, 8, 2, 3 }, /* 2 x 2 */
1492 { 3, 4, 2, 3 }, /* 4 x 4 */
1493 { 1, 2, 2, 3 }, /* 8 x 8 */
1494 { 0, 1, 2, 3 }, /* 16 x 16 */
1495 { 0, 1, 0, 1 }, /* 32 x 32 */
1497 struct GraphicInfo *g = &graphic_info[graphic];
1498 Bitmap *src_bitmap = g->bitmap;
1499 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1500 int offset_calc_pos = log_2(tilesize);
1501 int width_mult = offset_calc[offset_calc_pos].width_mult;
1502 int width_div = offset_calc[offset_calc_pos].width_div;
1503 int height_mult = offset_calc[offset_calc_pos].height_mult;
1504 int height_div = offset_calc[offset_calc_pos].height_div;
1505 int startx = src_bitmap->width * width_mult / width_div;
1506 int starty = src_bitmap->height * height_mult / height_div;
1508 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1509 tilesize / TILESIZE;
1510 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1511 tilesize / TILESIZE;
1513 int src_x = g->src_x * tilesize / TILESIZE;
1514 int src_y = g->src_y * tilesize / TILESIZE;
1516 int width = g->width * tilesize / TILESIZE;
1517 int height = g->height * tilesize / TILESIZE;
1518 int offset_x = g->offset_x * tilesize / TILESIZE;
1519 int offset_y = g->offset_y * tilesize / TILESIZE;
1521 if (g->offset_y == 0) /* frames are ordered horizontally */
1523 int max_width = g->anim_frames_per_line * width;
1524 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1526 src_x = pos % max_width;
1527 src_y = src_y % height + pos / max_width * height;
1529 else if (g->offset_x == 0) /* frames are ordered vertically */
1531 int max_height = g->anim_frames_per_line * height;
1532 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1534 src_x = src_x % width + pos / max_height * width;
1535 src_y = pos % max_height;
1537 else /* frames are ordered diagonally */
1539 src_x = src_x + frame * offset_x;
1540 src_y = src_y + frame * offset_y;
1543 *bitmap = src_bitmap;
1544 *x = startx + src_x;
1545 *y = starty + src_y;
1548 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1549 int *x, int *y, boolean get_backside)
1551 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1555 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1556 Bitmap **bitmap, int *x, int *y)
1558 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1561 void getFixedGraphicSource(int graphic, int frame,
1562 Bitmap **bitmap, int *x, int *y)
1564 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1567 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1570 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1572 struct GraphicInfo *g = &graphic_info[graphic];
1573 int mini_startx = 0;
1574 int mini_starty = g->bitmap->height * 2 / 3;
1576 *bitmap = g->bitmap;
1577 *x = mini_startx + g->src_x / 2;
1578 *y = mini_starty + g->src_y / 2;
1582 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1583 int *x, int *y, boolean get_backside)
1585 struct GraphicInfo *g = &graphic_info[graphic];
1586 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1587 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1590 if (TILESIZE_VAR != TILESIZE)
1591 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1595 *bitmap = g->bitmap;
1597 if (g->offset_y == 0) /* frames are ordered horizontally */
1599 int max_width = g->anim_frames_per_line * g->width;
1600 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1602 *x = pos % max_width;
1603 *y = src_y % g->height + pos / max_width * g->height;
1605 else if (g->offset_x == 0) /* frames are ordered vertically */
1607 int max_height = g->anim_frames_per_line * g->height;
1608 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1610 *x = src_x % g->width + pos / max_height * g->width;
1611 *y = pos % max_height;
1613 else /* frames are ordered diagonally */
1615 *x = src_x + frame * g->offset_x;
1616 *y = src_y + frame * g->offset_y;
1620 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1622 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1625 void DrawGraphic(int x, int y, int graphic, int frame)
1628 if (!IN_SCR_FIELD(x, y))
1630 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1631 printf("DrawGraphic(): This should never happen!\n");
1637 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1640 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1642 MarkTileDirty(x, y);
1645 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1648 if (!IN_SCR_FIELD(x, y))
1650 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1651 printf("DrawGraphic(): This should never happen!\n");
1656 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1658 MarkTileDirty(x, y);
1661 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1667 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1669 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1671 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1675 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1681 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1682 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1685 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1688 if (!IN_SCR_FIELD(x, y))
1690 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1691 printf("DrawGraphicThruMask(): This should never happen!\n");
1697 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1700 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1703 MarkTileDirty(x, y);
1706 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1709 if (!IN_SCR_FIELD(x, y))
1711 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1712 printf("DrawGraphicThruMask(): This should never happen!\n");
1717 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1719 MarkTileDirty(x, y);
1722 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1728 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1730 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1731 dst_x - src_x, dst_y - src_y);
1733 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1736 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1740 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1741 int graphic, int frame)
1746 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1748 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1749 dst_x - src_x, dst_y - src_y);
1750 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1753 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1755 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1757 MarkTileDirty(x / tilesize, y / tilesize);
1760 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1766 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1767 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1770 void DrawMiniGraphic(int x, int y, int graphic)
1772 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1773 MarkTileDirty(x / 2, y / 2);
1776 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1781 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1782 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1785 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1786 int graphic, int frame,
1787 int cut_mode, int mask_mode)
1792 int width = TILEX, height = TILEY;
1795 if (dx || dy) /* shifted graphic */
1797 if (x < BX1) /* object enters playfield from the left */
1804 else if (x > BX2) /* object enters playfield from the right */
1810 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1816 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1818 else if (dx) /* general horizontal movement */
1819 MarkTileDirty(x + SIGN(dx), y);
1821 if (y < BY1) /* object enters playfield from the top */
1823 if (cut_mode==CUT_BELOW) /* object completely above top border */
1831 else if (y > BY2) /* object enters playfield from the bottom */
1837 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1843 else if (dy > 0 && cut_mode == CUT_ABOVE)
1845 if (y == BY2) /* object completely above bottom border */
1851 MarkTileDirty(x, y + 1);
1852 } /* object leaves playfield to the bottom */
1853 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1855 else if (dy) /* general vertical movement */
1856 MarkTileDirty(x, y + SIGN(dy));
1860 if (!IN_SCR_FIELD(x, y))
1862 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1863 printf("DrawGraphicShifted(): This should never happen!\n");
1869 width = width * TILESIZE_VAR / TILESIZE;
1870 height = height * TILESIZE_VAR / TILESIZE;
1871 cx = cx * TILESIZE_VAR / TILESIZE;
1872 cy = cy * TILESIZE_VAR / TILESIZE;
1873 dx = dx * TILESIZE_VAR / TILESIZE;
1874 dy = dy * TILESIZE_VAR / TILESIZE;
1877 if (width > 0 && height > 0)
1879 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1885 dst_x = FX + x * TILEX_VAR + dx;
1886 dst_y = FY + y * TILEY_VAR + dy;
1888 dst_x = FX + x * TILEX + dx;
1889 dst_y = FY + y * TILEY + dy;
1892 if (mask_mode == USE_MASKING)
1894 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1895 dst_x - src_x, dst_y - src_y);
1896 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1900 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1903 MarkTileDirty(x, y);
1907 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1908 int graphic, int frame,
1909 int cut_mode, int mask_mode)
1915 int width = TILEX_VAR, height = TILEY_VAR;
1917 int width = TILEX, height = TILEY;
1921 int x2 = x + SIGN(dx);
1922 int y2 = y + SIGN(dy);
1924 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1925 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1927 /* movement with two-tile animations must be sync'ed with movement position,
1928 not with current GfxFrame (which can be higher when using slow movement) */
1929 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1930 int anim_frames = graphic_info[graphic].anim_frames;
1932 /* (we also need anim_delay here for movement animations with less frames) */
1933 int anim_delay = graphic_info[graphic].anim_delay;
1934 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1936 int sync_frame = anim_pos * anim_frames / TILESIZE;
1939 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1940 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1942 /* re-calculate animation frame for two-tile movement animation */
1943 frame = getGraphicAnimationFrame(graphic, sync_frame);
1947 printf("::: %d, %d, %d => %d [%d]\n",
1948 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1950 printf("::: %d, %d => %d\n",
1951 anim_pos, anim_frames, sync_frame);
1956 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1957 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1960 /* check if movement start graphic inside screen area and should be drawn */
1961 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1963 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1966 dst_x = FX + x1 * TILEX_VAR;
1967 dst_y = FY + y1 * TILEY_VAR;
1969 dst_x = FX + x1 * TILEX;
1970 dst_y = FY + y1 * TILEY;
1973 if (mask_mode == USE_MASKING)
1975 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1976 dst_x - src_x, dst_y - src_y);
1977 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1981 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1984 MarkTileDirty(x1, y1);
1987 /* check if movement end graphic inside screen area and should be drawn */
1988 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1990 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1993 dst_x = FX + x2 * TILEX_VAR;
1994 dst_y = FY + y2 * TILEY_VAR;
1996 dst_x = FX + x2 * TILEX;
1997 dst_y = FY + y2 * TILEY;
2000 if (mask_mode == USE_MASKING)
2002 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2003 dst_x - src_x, dst_y - src_y);
2004 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2008 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2011 MarkTileDirty(x2, y2);
2015 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2016 int graphic, int frame,
2017 int cut_mode, int mask_mode)
2021 DrawGraphic(x, y, graphic, frame);
2026 if (graphic_info[graphic].double_movement) /* EM style movement images */
2027 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2029 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2032 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2033 int frame, int cut_mode)
2035 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2038 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2039 int cut_mode, int mask_mode)
2041 int lx = LEVELX(x), ly = LEVELY(y);
2045 if (IN_LEV_FIELD(lx, ly))
2047 SetRandomAnimationValue(lx, ly);
2049 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2050 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2052 /* do not use double (EM style) movement graphic when not moving */
2053 if (graphic_info[graphic].double_movement && !dx && !dy)
2055 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2056 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2059 else /* border element */
2061 graphic = el2img(element);
2062 frame = getGraphicAnimationFrame(graphic, -1);
2065 if (element == EL_EXPANDABLE_WALL)
2067 boolean left_stopped = FALSE, right_stopped = FALSE;
2069 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2070 left_stopped = TRUE;
2071 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2072 right_stopped = TRUE;
2074 if (left_stopped && right_stopped)
2076 else if (left_stopped)
2078 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2079 frame = graphic_info[graphic].anim_frames - 1;
2081 else if (right_stopped)
2083 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2084 frame = graphic_info[graphic].anim_frames - 1;
2089 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2090 else if (mask_mode == USE_MASKING)
2091 DrawGraphicThruMask(x, y, graphic, frame);
2093 DrawGraphic(x, y, graphic, frame);
2096 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2097 int cut_mode, int mask_mode)
2099 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2100 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2101 cut_mode, mask_mode);
2104 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2107 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2110 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2113 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2116 void DrawLevelElementThruMask(int x, int y, int element)
2118 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2121 void DrawLevelFieldThruMask(int x, int y)
2123 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2126 /* !!! implementation of quicksand is totally broken !!! */
2127 #define IS_CRUMBLED_TILE(x, y, e) \
2128 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2129 !IS_MOVING(x, y) || \
2130 (e) == EL_QUICKSAND_EMPTYING || \
2131 (e) == EL_QUICKSAND_FAST_EMPTYING))
2133 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2138 int width, height, cx, cy;
2139 int sx = SCREENX(x), sy = SCREENY(y);
2140 int crumbled_border_size = graphic_info[graphic].border_size;
2143 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2145 for (i = 1; i < 4; i++)
2147 int dxx = (i & 1 ? dx : 0);
2148 int dyy = (i & 2 ? dy : 0);
2151 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2154 /* check if neighbour field is of same crumble type */
2155 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2156 graphic_info[graphic].class ==
2157 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2159 /* return if check prevents inner corner */
2160 if (same == (dxx == dx && dyy == dy))
2164 /* if we reach this point, we have an inner corner */
2166 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2169 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2170 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2171 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2172 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2174 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2175 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2177 width = crumbled_border_size;
2178 height = crumbled_border_size;
2179 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2180 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2182 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2183 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2187 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2192 int width, height, bx, by, cx, cy;
2193 int sx = SCREENX(x), sy = SCREENY(y);
2194 int crumbled_border_size = graphic_info[graphic].border_size;
2197 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2199 /* draw simple, sloppy, non-corner-accurate crumbled border */
2202 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2203 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2204 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2205 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2207 if (dir == 1 || dir == 2) /* left or right crumbled border */
2209 width = crumbled_border_size;
2211 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2214 else /* top or bottom crumbled border */
2217 height = crumbled_border_size;
2219 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2224 BlitBitmap(src_bitmap, drawto_field,
2225 src_x + cx * TILESIZE_VAR / TILESIZE,
2226 src_y + cy * TILESIZE_VAR / TILESIZE,
2227 width * TILESIZE_VAR / TILESIZE,
2228 height * TILESIZE_VAR / TILESIZE,
2229 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2230 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2232 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2233 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2236 /* (remaining middle border part must be at least as big as corner part) */
2237 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2238 crumbled_border_size >= TILESIZE / 3)
2241 /* correct corners of crumbled border, if needed */
2244 for (i = -1; i <= 1; i+=2)
2246 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2247 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2248 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2251 /* check if neighbour field is of same crumble type */
2252 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2253 graphic_info[graphic].class ==
2254 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2256 /* no crumbled corner, but continued crumbled border */
2258 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2259 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2260 int b1 = (i == 1 ? crumbled_border_size :
2261 TILESIZE - 2 * crumbled_border_size);
2263 width = crumbled_border_size;
2264 height = crumbled_border_size;
2266 if (dir == 1 || dir == 2)
2282 BlitBitmap(src_bitmap, drawto_field,
2283 src_x + bx * TILESIZE_VAR / TILESIZE,
2284 src_y + by * TILESIZE_VAR / TILESIZE,
2285 width * TILESIZE_VAR / TILESIZE,
2286 height * TILESIZE_VAR / TILESIZE,
2287 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2288 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2290 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2291 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2296 if (dir == 1 || dir == 2) /* left or right crumbled border */
2298 for (i = -1; i <= 1; i+=2)
2302 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2305 /* check if neighbour field is of same crumble type */
2306 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2307 graphic_info[graphic].class ==
2308 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2310 /* no crumbled corner, but continued crumbled border */
2312 width = crumbled_border_size;
2313 height = crumbled_border_size;
2314 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2315 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2317 by = (i == 1 ? crumbled_border_size :
2318 TILEY - 2 * crumbled_border_size);
2320 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2321 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2325 else /* top or bottom crumbled border */
2327 for (i = -1; i <= 1; i+=2)
2331 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2334 /* check if neighbour field is of same crumble type */
2335 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2336 graphic_info[graphic].class ==
2337 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2339 /* no crumbled corner, but continued crumbled border */
2341 width = crumbled_border_size;
2342 height = crumbled_border_size;
2343 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2344 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2345 bx = (i == 1 ? crumbled_border_size :
2346 TILEX - 2 * crumbled_border_size);
2349 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2350 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2357 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2359 int sx = SCREENX(x), sy = SCREENY(y);
2362 static int xy[4][2] =
2370 if (!IN_LEV_FIELD(x, y))
2373 element = TILE_GFX_ELEMENT(x, y);
2375 /* crumble field itself */
2376 if (IS_CRUMBLED_TILE(x, y, element))
2378 if (!IN_SCR_FIELD(sx, sy))
2381 for (i = 0; i < 4; i++)
2383 int xx = x + xy[i][0];
2384 int yy = y + xy[i][1];
2386 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2389 /* check if neighbour field is of same crumble type */
2391 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2392 graphic_info[graphic].class ==
2393 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2396 if (IS_CRUMBLED_TILE(xx, yy, element))
2400 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2403 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2404 graphic_info[graphic].anim_frames == 2)
2406 for (i = 0; i < 4; i++)
2408 int dx = (i & 1 ? +1 : -1);
2409 int dy = (i & 2 ? +1 : -1);
2411 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2415 MarkTileDirty(sx, sy);
2417 else /* center field not crumbled -- crumble neighbour fields */
2419 for (i = 0; i < 4; i++)
2421 int xx = x + xy[i][0];
2422 int yy = y + xy[i][1];
2423 int sxx = sx + xy[i][0];
2424 int syy = sy + xy[i][1];
2426 if (!IN_LEV_FIELD(xx, yy) ||
2427 !IN_SCR_FIELD(sxx, syy))
2430 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2433 element = TILE_GFX_ELEMENT(xx, yy);
2435 if (!IS_CRUMBLED_TILE(xx, yy, element))
2438 graphic = el_act2crm(element, ACTION_DEFAULT);
2440 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2442 MarkTileDirty(sxx, syy);
2447 void DrawLevelFieldCrumbled(int x, int y)
2451 if (!IN_LEV_FIELD(x, y))
2455 /* !!! CHECK THIS !!! */
2458 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2459 GFX_CRUMBLED(GfxElement[x][y]))
2462 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2463 GfxElement[x][y] != EL_UNDEFINED &&
2464 GFX_CRUMBLED(GfxElement[x][y]))
2466 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2473 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2475 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2478 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2481 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2484 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2485 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2486 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2487 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2488 int sx = SCREENX(x), sy = SCREENY(y);
2490 DrawGraphic(sx, sy, graphic1, frame1);
2491 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2494 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2496 int sx = SCREENX(x), sy = SCREENY(y);
2497 static int xy[4][2] =
2506 for (i = 0; i < 4; i++)
2508 int xx = x + xy[i][0];
2509 int yy = y + xy[i][1];
2510 int sxx = sx + xy[i][0];
2511 int syy = sy + xy[i][1];
2513 if (!IN_LEV_FIELD(xx, yy) ||
2514 !IN_SCR_FIELD(sxx, syy) ||
2515 !GFX_CRUMBLED(Feld[xx][yy]) ||
2519 DrawLevelField(xx, yy);
2523 static int getBorderElement(int x, int y)
2527 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2528 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2529 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2530 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2531 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2532 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2533 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2535 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2536 int steel_position = (x == -1 && y == -1 ? 0 :
2537 x == lev_fieldx && y == -1 ? 1 :
2538 x == -1 && y == lev_fieldy ? 2 :
2539 x == lev_fieldx && y == lev_fieldy ? 3 :
2540 x == -1 || x == lev_fieldx ? 4 :
2541 y == -1 || y == lev_fieldy ? 5 : 6);
2543 return border[steel_position][steel_type];
2546 void DrawScreenElement(int x, int y, int element)
2548 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2549 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2552 void DrawLevelElement(int x, int y, int element)
2554 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2555 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2558 void DrawScreenField(int x, int y)
2560 int lx = LEVELX(x), ly = LEVELY(y);
2561 int element, content;
2563 if (!IN_LEV_FIELD(lx, ly))
2565 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2568 element = getBorderElement(lx, ly);
2570 DrawScreenElement(x, y, element);
2575 element = Feld[lx][ly];
2576 content = Store[lx][ly];
2578 if (IS_MOVING(lx, ly))
2580 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2581 boolean cut_mode = NO_CUTTING;
2583 if (element == EL_QUICKSAND_EMPTYING ||
2584 element == EL_QUICKSAND_FAST_EMPTYING ||
2585 element == EL_MAGIC_WALL_EMPTYING ||
2586 element == EL_BD_MAGIC_WALL_EMPTYING ||
2587 element == EL_DC_MAGIC_WALL_EMPTYING ||
2588 element == EL_AMOEBA_DROPPING)
2589 cut_mode = CUT_ABOVE;
2590 else if (element == EL_QUICKSAND_FILLING ||
2591 element == EL_QUICKSAND_FAST_FILLING ||
2592 element == EL_MAGIC_WALL_FILLING ||
2593 element == EL_BD_MAGIC_WALL_FILLING ||
2594 element == EL_DC_MAGIC_WALL_FILLING)
2595 cut_mode = CUT_BELOW;
2598 if (lx == 9 && ly == 1)
2599 printf("::: %s [%d] [%d, %d] [%d]\n",
2600 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2601 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2602 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2603 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2604 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2607 if (cut_mode == CUT_ABOVE)
2609 DrawScreenElement(x, y, element);
2611 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2614 DrawScreenElement(x, y, EL_EMPTY);
2617 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2618 else if (cut_mode == NO_CUTTING)
2619 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2622 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2625 if (cut_mode == CUT_BELOW &&
2626 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2627 DrawLevelElement(lx, ly + 1, element);
2631 if (content == EL_ACID)
2633 int dir = MovDir[lx][ly];
2634 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2635 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2637 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2640 else if (IS_BLOCKED(lx, ly))
2645 boolean cut_mode = NO_CUTTING;
2646 int element_old, content_old;
2648 Blocked2Moving(lx, ly, &oldx, &oldy);
2651 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2652 MovDir[oldx][oldy] == MV_RIGHT);
2654 element_old = Feld[oldx][oldy];
2655 content_old = Store[oldx][oldy];
2657 if (element_old == EL_QUICKSAND_EMPTYING ||
2658 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2659 element_old == EL_MAGIC_WALL_EMPTYING ||
2660 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2661 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2662 element_old == EL_AMOEBA_DROPPING)
2663 cut_mode = CUT_ABOVE;
2665 DrawScreenElement(x, y, EL_EMPTY);
2668 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2670 else if (cut_mode == NO_CUTTING)
2671 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2674 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2677 else if (IS_DRAWABLE(element))
2678 DrawScreenElement(x, y, element);
2680 DrawScreenElement(x, y, EL_EMPTY);
2683 void DrawLevelField(int x, int y)
2685 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2686 DrawScreenField(SCREENX(x), SCREENY(y));
2687 else if (IS_MOVING(x, y))
2691 Moving2Blocked(x, y, &newx, &newy);
2692 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2693 DrawScreenField(SCREENX(newx), SCREENY(newy));
2695 else if (IS_BLOCKED(x, y))
2699 Blocked2Moving(x, y, &oldx, &oldy);
2700 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2701 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2705 void DrawMiniElement(int x, int y, int element)
2709 graphic = el2edimg(element);
2710 DrawMiniGraphic(x, y, graphic);
2713 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2715 int x = sx + scroll_x, y = sy + scroll_y;
2717 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2718 DrawMiniElement(sx, sy, EL_EMPTY);
2719 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2720 DrawMiniElement(sx, sy, Feld[x][y]);
2722 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2725 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2726 int x, int y, int xsize, int ysize,
2727 int tile_width, int tile_height)
2731 int dst_x = startx + x * tile_width;
2732 int dst_y = starty + y * tile_height;
2733 int width = graphic_info[graphic].width;
2734 int height = graphic_info[graphic].height;
2735 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2736 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2737 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2738 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2739 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2740 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2741 boolean draw_masked = graphic_info[graphic].draw_masked;
2743 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2745 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2747 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2751 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2752 inner_sx + (x - 1) * tile_width % inner_width);
2753 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2754 inner_sy + (y - 1) * tile_height % inner_height);
2758 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2759 dst_x - src_x, dst_y - src_y);
2760 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2764 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2768 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2769 int x, int y, int xsize, int ysize, int font_nr)
2771 int font_width = getFontWidth(font_nr);
2772 int font_height = getFontHeight(font_nr);
2774 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2775 font_width, font_height);
2778 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2780 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2781 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2782 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2783 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2784 boolean no_delay = (tape.warp_forward);
2785 unsigned int anim_delay = 0;
2786 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2787 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2788 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2789 int font_width = getFontWidth(font_nr);
2790 int font_height = getFontHeight(font_nr);
2791 int max_xsize = level.envelope[envelope_nr].xsize;
2792 int max_ysize = level.envelope[envelope_nr].ysize;
2793 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2794 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2795 int xend = max_xsize;
2796 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2797 int xstep = (xstart < xend ? 1 : 0);
2798 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2801 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2803 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2804 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2805 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2806 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2809 SetDrawtoField(DRAW_BUFFERED);
2812 BlitScreenToBitmap(backbuffer);
2814 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2817 SetDrawtoField(DRAW_BACKBUFFER);
2819 for (yy = 0; yy < ysize; yy++)
2820 for (xx = 0; xx < xsize; xx++)
2821 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2824 DrawTextBuffer(sx + font_width, sy + font_height,
2825 level.envelope[envelope_nr].text, font_nr, max_xsize,
2826 xsize - 2, ysize - 2, 0, mask_mode,
2827 level.envelope[envelope_nr].autowrap,
2828 level.envelope[envelope_nr].centered, FALSE);
2830 DrawTextToTextArea(sx + font_width, sy + font_height,
2831 level.envelope[envelope_nr].text, font_nr, max_xsize,
2832 xsize - 2, ysize - 2, mask_mode);
2835 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2838 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2842 void ShowEnvelope(int envelope_nr)
2844 int element = EL_ENVELOPE_1 + envelope_nr;
2845 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2846 int sound_opening = element_info[element].sound[ACTION_OPENING];
2847 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2848 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2849 boolean no_delay = (tape.warp_forward);
2850 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2851 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2852 int anim_mode = graphic_info[graphic].anim_mode;
2853 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2854 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2856 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2858 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2860 if (anim_mode == ANIM_DEFAULT)
2861 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2863 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2866 Delay(wait_delay_value);
2868 WaitForEventToContinue();
2870 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2872 if (anim_mode != ANIM_NONE)
2873 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2875 if (anim_mode == ANIM_DEFAULT)
2876 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2878 game.envelope_active = FALSE;
2880 SetDrawtoField(DRAW_BUFFERED);
2882 redraw_mask |= REDRAW_FIELD;
2886 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2888 int border_size = request.border_size;
2889 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2890 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2891 int sx = sx_center - request.width / 2;
2892 int sy = sy_center - request.height / 2;
2894 if (add_border_size)
2904 void DrawEnvelopeRequest(char *text)
2906 char *text_final = text;
2907 char *text_door_style = NULL;
2908 int graphic = IMG_BACKGROUND_REQUEST;
2909 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2910 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2911 int font_nr = FONT_REQUEST;
2912 int font_width = getFontWidth(font_nr);
2913 int font_height = getFontHeight(font_nr);
2914 int border_size = request.border_size;
2915 int line_spacing = request.line_spacing;
2916 int line_height = font_height + line_spacing;
2917 int text_width = request.width - 2 * border_size;
2918 int text_height = request.height - 2 * border_size;
2919 int line_length = text_width / font_width;
2920 int max_lines = text_height / line_height;
2921 int width = request.width;
2922 int height = request.height;
2923 int tile_size = request.step_offset;
2924 int x_steps = width / tile_size;
2925 int y_steps = height / tile_size;
2929 if (request.wrap_single_words)
2931 char *src_text_ptr, *dst_text_ptr;
2933 text_door_style = checked_malloc(2 * strlen(text) + 1);
2935 src_text_ptr = text;
2936 dst_text_ptr = text_door_style;
2938 while (*src_text_ptr)
2940 if (*src_text_ptr == ' ' ||
2941 *src_text_ptr == '?' ||
2942 *src_text_ptr == '!')
2943 *dst_text_ptr++ = '\n';
2945 if (*src_text_ptr != ' ')
2946 *dst_text_ptr++ = *src_text_ptr;
2951 *dst_text_ptr = '\0';
2953 text_final = text_door_style;
2956 setRequestPosition(&sx, &sy, FALSE);
2958 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2960 for (y = 0; y < y_steps; y++)
2961 for (x = 0; x < x_steps; x++)
2962 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2963 x, y, x_steps, y_steps,
2964 tile_size, tile_size);
2966 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2967 line_length, -1, max_lines, line_spacing, mask_mode,
2968 request.autowrap, request.centered, FALSE);
2970 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2971 RedrawGadget(tool_gadget[i]);
2973 // store readily prepared envelope request for later use when animating
2974 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2978 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2979 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2981 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2986 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2988 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2994 if (text_door_style)
2995 free(text_door_style);
3000 void AnimateEnvelopeRequest(int anim_mode, int action)
3002 int graphic = IMG_BACKGROUND_REQUEST;
3003 boolean draw_masked = graphic_info[graphic].draw_masked;
3005 int delay_value_normal = request.step_delay;
3006 int delay_value_fast = delay_value_normal / 2;
3008 int delay_value_normal = GameFrameDelay;
3009 int delay_value_fast = FfwdFrameDelay;
3011 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3012 boolean no_delay = (tape.warp_forward);
3013 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3014 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3015 unsigned int anim_delay = 0;
3017 int width = request.width;
3018 int height = request.height;
3019 int tile_size = request.step_offset;
3020 int max_xsize = width / tile_size;
3021 int max_ysize = height / tile_size;
3022 int max_xsize_inner = max_xsize - 2;
3023 int max_ysize_inner = max_ysize - 2;
3025 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3026 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3027 int xend = max_xsize_inner;
3028 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3029 int xstep = (xstart < xend ? 1 : 0);
3030 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3033 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3035 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3036 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3037 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3038 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3039 int src_x = sx_center - width / 2;
3040 int src_y = sy_center - height / 2;
3041 int dst_x = sx_center - xsize * tile_size / 2;
3042 int dst_y = sy_center - ysize * tile_size / 2;
3043 int xsize_size_left = (xsize - 1) * tile_size;
3044 int ysize_size_top = (ysize - 1) * tile_size;
3045 int max_xsize_pos = (max_xsize - 1) * tile_size;
3046 int max_ysize_pos = (max_ysize - 1) * tile_size;
3049 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3052 for (yy = 0; yy < 2; yy++)
3054 for (xx = 0; xx < 2; xx++)
3056 int src_xx = src_x + xx * max_xsize_pos;
3057 int src_yy = src_y + yy * max_ysize_pos;
3058 int dst_xx = dst_x + xx * xsize_size_left;
3059 int dst_yy = dst_y + yy * ysize_size_top;
3060 int xx_size = (xx ? tile_size : xsize_size_left);
3061 int yy_size = (yy ? tile_size : ysize_size_top);
3064 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3065 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3067 BlitBitmap(bitmap_db_cross, backbuffer,
3068 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3072 BlitBitmap(bitmap_db_cross, backbuffer,
3074 xsize_size_left, ysize_size_top,
3076 BlitBitmap(bitmap_db_cross, backbuffer,
3077 src_x + max_xsize_pos, src_y,
3078 tile_size, ysize_size_top,
3079 dst_x + xsize_size_left, dst_y);
3080 BlitBitmap(bitmap_db_cross, backbuffer,
3081 src_x, src_y + max_ysize_pos,
3082 xsize_size_left, tile_size,
3083 dst_x, dst_y + ysize_size_top);
3084 BlitBitmap(bitmap_db_cross, backbuffer,
3085 src_x + max_xsize_pos, src_y + max_ysize_pos,
3086 tile_size, tile_size,
3087 dst_x + xsize_size_left, dst_y + ysize_size_top);
3091 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3092 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3094 /* CHECK AGAIN (previous code reactivated) */
3095 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3105 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3111 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3114 int envelope_nr = 0;
3117 int graphic = IMG_BACKGROUND_REQUEST;
3119 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3121 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3122 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3123 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3124 boolean no_delay = (tape.warp_forward);
3125 unsigned int anim_delay = 0;
3126 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3127 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3129 int max_word_len = maxWordLengthInString(text);
3130 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3132 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3134 int font_width = getFontWidth(font_nr);
3135 int font_height = getFontHeight(font_nr);
3136 int line_spacing = 2 * 1;
3140 int max_xsize = DXSIZE / font_width;
3141 // int max_ysize = DYSIZE / font_height;
3142 int max_ysize = DYSIZE / (font_height + line_spacing);
3144 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3145 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3149 int max_xsize = level.envelope[envelope_nr].xsize;
3150 int max_ysize = level.envelope[envelope_nr].ysize;
3152 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3153 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3154 int xend = max_xsize;
3155 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3156 int xstep = (xstart < xend ? 1 : 0);
3157 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3162 char *text_copy = getStringCopy(text);
3165 font_nr = FONT_TEXT_2;
3167 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3169 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3170 font_nr = FONT_TEXT_1;
3173 int max_word_len = 0;
3175 char *text_copy = getStringCopy(text);
3177 font_nr = FONT_TEXT_2;
3179 for (text_ptr = text; *text_ptr; text_ptr++)
3181 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3183 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3185 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3186 font_nr = FONT_TEXT_1;
3195 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3196 if (*text_ptr == ' ')
3201 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3202 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3204 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3205 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3208 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3210 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3211 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3212 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3213 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3214 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3218 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3220 SetDrawtoField(DRAW_BUFFERED);
3223 BlitScreenToBitmap(backbuffer);
3225 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3228 SetDrawtoField(DRAW_BACKBUFFER);
3231 for (yy = 0; yy < ysize; yy++)
3232 for (xx = 0; xx < xsize; xx++)
3233 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3234 getFontWidth(font_nr),
3235 getFontHeight(font_nr) + line_spacing);
3240 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3241 text_copy, font_nr, max_xsize,
3242 xsize - 2, ysize - 2, line_spacing, mask_mode,
3243 FALSE, TRUE, FALSE);
3245 DrawTextBuffer(sx + font_width, sy + font_height,
3246 level.envelope[envelope_nr].text, font_nr, max_xsize,
3247 xsize - 2, ysize - 2, 0, mask_mode,
3248 level.envelope[envelope_nr].autowrap,
3249 level.envelope[envelope_nr].centered, FALSE);
3253 DrawTextToTextArea(sx + font_width, sy + font_height,
3254 level.envelope[envelope_nr].text, font_nr, max_xsize,
3255 xsize - 2, ysize - 2, mask_mode);
3258 /* copy request gadgets to door backbuffer */
3261 if ((ysize - 2) > 13)
3262 BlitBitmap(bitmap_db_door, drawto,
3263 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3264 DOOR_GFX_PAGEY1 + 13 * font_height,
3265 (xsize - 2) * font_width,
3266 (ysize - 2 - 13) * font_height,
3268 sy + font_height * (1 + 13));
3270 if ((ysize - 2) > 13)
3271 BlitBitmap(bitmap_db_door, drawto,
3272 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3273 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3274 (xsize - 2) * font_width,
3275 (ysize - 2 - 13) * (font_height + line_spacing),
3277 sy + (font_height + line_spacing) * (1 + 13));
3279 if ((ysize - 2) > 13)
3280 BlitBitmap(bitmap_db_door, drawto,
3281 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3282 DOOR_GFX_PAGEY1 + 13 * font_height,
3283 (xsize - 2) * font_width,
3284 (ysize - 2 - 13) * font_height,
3286 sy + font_height * (1 + 13));
3290 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3291 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3293 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3303 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3313 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3316 int last_game_status = game_status; /* save current game status */
3317 // int last_draw_background_mask = gfx.draw_background_mask;
3320 int graphic = IMG_BACKGROUND_REQUEST;
3321 int sound_opening = SND_REQUEST_OPENING;
3322 int sound_closing = SND_REQUEST_CLOSING;
3324 int envelope_nr = 0;
3325 int element = EL_ENVELOPE_1 + envelope_nr;
3326 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3327 int sound_opening = element_info[element].sound[ACTION_OPENING];
3328 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3331 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3332 boolean no_delay = (tape.warp_forward);
3333 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3334 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3336 int anim_mode = graphic_info[graphic].anim_mode;
3337 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3338 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3340 char *text_copy = getStringCopy(text);
3343 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3344 if (*text_ptr == ' ')
3349 if (game_status == GAME_MODE_PLAYING)
3353 BlitScreenToBitmap(backbuffer);
3355 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3356 BlitScreenToBitmap_EM(backbuffer);
3357 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3358 BlitScreenToBitmap_SP(backbuffer);
3360 BlitScreenToBitmap_RND(backbuffer);
3363 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3364 BlitScreenToBitmap_EM(backbuffer);
3365 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3366 BlitScreenToBitmap_SP(backbuffer);
3369 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3374 SetDrawtoField(DRAW_BACKBUFFER);
3376 // SetDrawBackgroundMask(REDRAW_NONE);
3378 if (action == ACTION_OPENING)
3380 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3383 if (req_state & REQ_ASK)
3385 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3386 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3388 else if (req_state & REQ_CONFIRM)
3390 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3392 else if (req_state & REQ_PLAYER)
3394 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3395 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3396 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3397 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3402 DrawEnvelopeRequest(text);
3404 DrawEnvelopeRequest(text_copy);
3407 if (game_status != GAME_MODE_MAIN)
3411 /* force DOOR font inside door area */
3412 game_status = GAME_MODE_PSEUDO_DOOR;
3415 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3417 if (action == ACTION_OPENING)
3419 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3421 if (anim_mode == ANIM_DEFAULT)
3422 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3424 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3428 Delay(wait_delay_value);
3430 WaitForEventToContinue();
3435 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3437 if (anim_mode != ANIM_NONE)
3438 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3440 if (anim_mode == ANIM_DEFAULT)
3441 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3444 game.envelope_active = FALSE;
3447 // game_status = last_game_status; /* restore current game status */
3450 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3451 game_status = last_game_status; /* restore current game status */
3454 if (action == ACTION_CLOSING)
3456 if (game_status != GAME_MODE_MAIN)
3459 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3462 SetDrawtoField(DRAW_BUFFERED);
3465 // SetDrawBackgroundMask(last_draw_background_mask);
3468 redraw_mask = REDRAW_FIELD;
3469 // redraw_mask |= REDRAW_ALL;
3471 /* CHECK AGAIN (previous code reactivated) */
3472 redraw_mask |= REDRAW_FIELD;
3476 if (game_status == GAME_MODE_MAIN)
3482 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3483 game_status = last_game_status; /* restore current game status */
3487 if (action == ACTION_CLOSING &&
3488 game_status == GAME_MODE_PLAYING &&
3489 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3490 SetDrawtoField(DRAW_BUFFERED);
3492 if (game_status == GAME_MODE_PLAYING &&
3493 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3494 SetDrawtoField(DRAW_BUFFERED);
3506 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3510 int graphic = el2preimg(element);
3512 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3513 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3521 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3522 SetDrawBackgroundMask(REDRAW_FIELD);
3524 SetDrawBackgroundMask(REDRAW_NONE);
3529 for (x = BX1; x <= BX2; x++)
3530 for (y = BY1; y <= BY2; y++)
3531 DrawScreenField(x, y);
3533 redraw_mask |= REDRAW_FIELD;
3536 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3540 for (x = 0; x < size_x; x++)
3541 for (y = 0; y < size_y; y++)
3542 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3544 redraw_mask |= REDRAW_FIELD;
3547 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3549 boolean show_level_border = (BorderElement != EL_EMPTY);
3550 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3551 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3552 int tile_size = preview.tile_size;
3553 int preview_width = preview.xsize * tile_size;
3554 int preview_height = preview.ysize * tile_size;
3555 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3556 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3557 int real_preview_width = real_preview_xsize * tile_size;
3558 int real_preview_height = real_preview_ysize * tile_size;
3559 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3560 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3564 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3569 dst_x += (preview_width - real_preview_width) / 2;
3570 dst_y += (preview_height - real_preview_height) / 2;
3572 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3574 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3576 dst_x += (preview_width - real_preview_width) / 2;
3577 dst_y += (preview_height - real_preview_height) / 2;
3580 for (x = 0; x < real_preview_xsize; x++)
3582 for (y = 0; y < real_preview_ysize; y++)
3584 int lx = from_x + x + (show_level_border ? -1 : 0);
3585 int ly = from_y + y + (show_level_border ? -1 : 0);
3586 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3587 getBorderElement(lx, ly));
3589 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3590 element, tile_size);
3594 redraw_mask |= REDRAW_MICROLEVEL;
3597 #define MICROLABEL_EMPTY 0
3598 #define MICROLABEL_LEVEL_NAME 1
3599 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3600 #define MICROLABEL_LEVEL_AUTHOR 3
3601 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3602 #define MICROLABEL_IMPORTED_FROM 5
3603 #define MICROLABEL_IMPORTED_BY_HEAD 6
3604 #define MICROLABEL_IMPORTED_BY 7
3606 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3608 int max_text_width = SXSIZE;
3609 int font_width = getFontWidth(font_nr);
3611 if (pos->align == ALIGN_CENTER)
3612 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3613 else if (pos->align == ALIGN_RIGHT)
3614 max_text_width = pos->x;
3616 max_text_width = SXSIZE - pos->x;
3618 return max_text_width / font_width;
3621 static void DrawPreviewLevelLabelExt(int mode)
3623 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3624 char label_text[MAX_OUTPUT_LINESIZE + 1];
3625 int max_len_label_text;
3627 int font_nr = pos->font;
3630 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3633 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3634 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3635 mode == MICROLABEL_IMPORTED_BY_HEAD)
3636 font_nr = pos->font_alt;
3638 int font_nr = FONT_TEXT_2;
3641 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3642 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3643 mode == MICROLABEL_IMPORTED_BY_HEAD)
3644 font_nr = FONT_TEXT_3;
3648 max_len_label_text = getMaxTextLength(pos, font_nr);
3650 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3654 if (pos->size != -1)
3655 max_len_label_text = pos->size;
3658 for (i = 0; i < max_len_label_text; i++)
3659 label_text[i] = ' ';
3660 label_text[max_len_label_text] = '\0';
3662 if (strlen(label_text) > 0)
3665 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3667 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3668 int lypos = MICROLABEL2_YPOS;
3670 DrawText(lxpos, lypos, label_text, font_nr);
3675 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3676 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3677 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3678 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3679 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3680 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3681 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3682 max_len_label_text);
3683 label_text[max_len_label_text] = '\0';
3685 if (strlen(label_text) > 0)
3688 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3690 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3691 int lypos = MICROLABEL2_YPOS;
3693 DrawText(lxpos, lypos, label_text, font_nr);
3697 redraw_mask |= REDRAW_MICROLEVEL;
3700 static void DrawPreviewLevelExt(boolean restart)
3702 static unsigned int scroll_delay = 0;
3703 static unsigned int label_delay = 0;
3704 static int from_x, from_y, scroll_direction;
3705 static int label_state, label_counter;
3706 unsigned int scroll_delay_value = preview.step_delay;
3707 boolean show_level_border = (BorderElement != EL_EMPTY);
3708 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3709 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3710 int last_game_status = game_status; /* save current game status */
3713 /* force PREVIEW font on preview level */
3714 game_status = GAME_MODE_PSEUDO_PREVIEW;
3722 if (preview.anim_mode == ANIM_CENTERED)
3724 if (level_xsize > preview.xsize)
3725 from_x = (level_xsize - preview.xsize) / 2;
3726 if (level_ysize > preview.ysize)
3727 from_y = (level_ysize - preview.ysize) / 2;
3730 from_x += preview.xoffset;
3731 from_y += preview.yoffset;
3733 scroll_direction = MV_RIGHT;
3737 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3738 DrawPreviewLevelLabelExt(label_state);
3740 /* initialize delay counters */
3741 DelayReached(&scroll_delay, 0);
3742 DelayReached(&label_delay, 0);
3744 if (leveldir_current->name)
3746 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3747 char label_text[MAX_OUTPUT_LINESIZE + 1];
3749 int font_nr = pos->font;
3751 int font_nr = FONT_TEXT_1;
3754 int max_len_label_text = getMaxTextLength(pos, font_nr);
3756 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3764 if (pos->size != -1)
3765 max_len_label_text = pos->size;
3768 strncpy(label_text, leveldir_current->name, max_len_label_text);
3769 label_text[max_len_label_text] = '\0';
3772 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3773 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3775 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3776 lypos = SY + MICROLABEL1_YPOS;
3778 DrawText(lxpos, lypos, label_text, font_nr);
3782 game_status = last_game_status; /* restore current game status */
3787 /* scroll preview level, if needed */
3788 if (preview.anim_mode != ANIM_NONE &&
3789 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3790 DelayReached(&scroll_delay, scroll_delay_value))
3792 switch (scroll_direction)
3797 from_x -= preview.step_offset;
3798 from_x = (from_x < 0 ? 0 : from_x);
3801 scroll_direction = MV_UP;
3805 if (from_x < level_xsize - preview.xsize)
3807 from_x += preview.step_offset;
3808 from_x = (from_x > level_xsize - preview.xsize ?
3809 level_xsize - preview.xsize : from_x);
3812 scroll_direction = MV_DOWN;
3818 from_y -= preview.step_offset;
3819 from_y = (from_y < 0 ? 0 : from_y);
3822 scroll_direction = MV_RIGHT;
3826 if (from_y < level_ysize - preview.ysize)
3828 from_y += preview.step_offset;
3829 from_y = (from_y > level_ysize - preview.ysize ?
3830 level_ysize - preview.ysize : from_y);
3833 scroll_direction = MV_LEFT;
3840 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3843 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3844 /* redraw micro level label, if needed */
3845 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3846 !strEqual(level.author, ANONYMOUS_NAME) &&
3847 !strEqual(level.author, leveldir_current->name) &&
3848 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3850 int max_label_counter = 23;
3852 if (leveldir_current->imported_from != NULL &&
3853 strlen(leveldir_current->imported_from) > 0)
3854 max_label_counter += 14;
3855 if (leveldir_current->imported_by != NULL &&
3856 strlen(leveldir_current->imported_by) > 0)
3857 max_label_counter += 14;
3859 label_counter = (label_counter + 1) % max_label_counter;
3860 label_state = (label_counter >= 0 && label_counter <= 7 ?
3861 MICROLABEL_LEVEL_NAME :
3862 label_counter >= 9 && label_counter <= 12 ?
3863 MICROLABEL_LEVEL_AUTHOR_HEAD :
3864 label_counter >= 14 && label_counter <= 21 ?
3865 MICROLABEL_LEVEL_AUTHOR :
3866 label_counter >= 23 && label_counter <= 26 ?
3867 MICROLABEL_IMPORTED_FROM_HEAD :
3868 label_counter >= 28 && label_counter <= 35 ?
3869 MICROLABEL_IMPORTED_FROM :
3870 label_counter >= 37 && label_counter <= 40 ?
3871 MICROLABEL_IMPORTED_BY_HEAD :
3872 label_counter >= 42 && label_counter <= 49 ?
3873 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3875 if (leveldir_current->imported_from == NULL &&
3876 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3877 label_state == MICROLABEL_IMPORTED_FROM))
3878 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3879 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3881 DrawPreviewLevelLabelExt(label_state);
3884 game_status = last_game_status; /* restore current game status */
3887 void DrawPreviewLevelInitial()
3889 DrawPreviewLevelExt(TRUE);
3892 void DrawPreviewLevelAnimation()
3894 DrawPreviewLevelExt(FALSE);
3897 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3898 int graphic, int sync_frame, int mask_mode)
3900 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3902 if (mask_mode == USE_MASKING)
3903 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3905 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3908 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3909 int graphic, int sync_frame,
3912 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3914 if (mask_mode == USE_MASKING)
3915 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3917 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3920 inline void DrawGraphicAnimation(int x, int y, int graphic)
3922 int lx = LEVELX(x), ly = LEVELY(y);
3924 if (!IN_SCR_FIELD(x, y))
3928 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3929 graphic, GfxFrame[lx][ly], NO_MASKING);
3931 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3932 graphic, GfxFrame[lx][ly], NO_MASKING);
3934 MarkTileDirty(x, y);
3937 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3939 int lx = LEVELX(x), ly = LEVELY(y);
3941 if (!IN_SCR_FIELD(x, y))
3944 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3945 graphic, GfxFrame[lx][ly], NO_MASKING);
3946 MarkTileDirty(x, y);
3949 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3951 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3954 void DrawLevelElementAnimation(int x, int y, int element)
3956 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3958 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3961 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3963 int sx = SCREENX(x), sy = SCREENY(y);
3965 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3968 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3971 DrawGraphicAnimation(sx, sy, graphic);
3974 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3975 DrawLevelFieldCrumbled(x, y);
3977 if (GFX_CRUMBLED(Feld[x][y]))
3978 DrawLevelFieldCrumbled(x, y);
3982 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3984 int sx = SCREENX(x), sy = SCREENY(y);
3987 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3990 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3992 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3995 DrawGraphicAnimation(sx, sy, graphic);
3997 if (GFX_CRUMBLED(element))
3998 DrawLevelFieldCrumbled(x, y);
4001 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4003 if (player->use_murphy)
4005 /* this works only because currently only one player can be "murphy" ... */
4006 static int last_horizontal_dir = MV_LEFT;
4007 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4009 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4010 last_horizontal_dir = move_dir;
4012 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4014 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4016 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4022 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4025 static boolean equalGraphics(int graphic1, int graphic2)
4027 struct GraphicInfo *g1 = &graphic_info[graphic1];
4028 struct GraphicInfo *g2 = &graphic_info[graphic2];
4030 return (g1->bitmap == g2->bitmap &&
4031 g1->src_x == g2->src_x &&
4032 g1->src_y == g2->src_y &&
4033 g1->anim_frames == g2->anim_frames &&
4034 g1->anim_delay == g2->anim_delay &&
4035 g1->anim_mode == g2->anim_mode);
4038 void DrawAllPlayers()
4042 for (i = 0; i < MAX_PLAYERS; i++)
4043 if (stored_player[i].active)
4044 DrawPlayer(&stored_player[i]);
4047 void DrawPlayerField(int x, int y)
4049 if (!IS_PLAYER(x, y))
4052 DrawPlayer(PLAYERINFO(x, y));
4055 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4057 void DrawPlayer(struct PlayerInfo *player)
4059 int jx = player->jx;
4060 int jy = player->jy;
4061 int move_dir = player->MovDir;
4062 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4063 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4064 int last_jx = (player->is_moving ? jx - dx : jx);
4065 int last_jy = (player->is_moving ? jy - dy : jy);
4066 int next_jx = jx + dx;
4067 int next_jy = jy + dy;
4068 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4069 boolean player_is_opaque = FALSE;
4070 int sx = SCREENX(jx), sy = SCREENY(jy);
4071 int sxx = 0, syy = 0;
4072 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4074 int action = ACTION_DEFAULT;
4075 int last_player_graphic = getPlayerGraphic(player, move_dir);
4076 int last_player_frame = player->Frame;
4079 /* GfxElement[][] is set to the element the player is digging or collecting;
4080 remove also for off-screen player if the player is not moving anymore */
4081 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4082 GfxElement[jx][jy] = EL_UNDEFINED;
4084 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4088 if (!IN_LEV_FIELD(jx, jy))
4090 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4091 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4092 printf("DrawPlayerField(): This should never happen!\n");
4097 if (element == EL_EXPLOSION)
4100 action = (player->is_pushing ? ACTION_PUSHING :
4101 player->is_digging ? ACTION_DIGGING :
4102 player->is_collecting ? ACTION_COLLECTING :
4103 player->is_moving ? ACTION_MOVING :
4104 player->is_snapping ? ACTION_SNAPPING :
4105 player->is_dropping ? ACTION_DROPPING :
4106 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4108 if (player->is_waiting)
4109 move_dir = player->dir_waiting;
4111 InitPlayerGfxAnimation(player, action, move_dir);
4113 /* ----------------------------------------------------------------------- */
4114 /* draw things in the field the player is leaving, if needed */
4115 /* ----------------------------------------------------------------------- */
4117 if (player->is_moving)
4119 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4121 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4123 if (last_element == EL_DYNAMITE_ACTIVE ||
4124 last_element == EL_EM_DYNAMITE_ACTIVE ||
4125 last_element == EL_SP_DISK_RED_ACTIVE)
4126 DrawDynamite(last_jx, last_jy);
4128 DrawLevelFieldThruMask(last_jx, last_jy);
4130 else if (last_element == EL_DYNAMITE_ACTIVE ||
4131 last_element == EL_EM_DYNAMITE_ACTIVE ||
4132 last_element == EL_SP_DISK_RED_ACTIVE)
4133 DrawDynamite(last_jx, last_jy);
4135 /* !!! this is not enough to prevent flickering of players which are
4136 moving next to each others without a free tile between them -- this
4137 can only be solved by drawing all players layer by layer (first the
4138 background, then the foreground etc.) !!! => TODO */
4139 else if (!IS_PLAYER(last_jx, last_jy))
4140 DrawLevelField(last_jx, last_jy);
4143 DrawLevelField(last_jx, last_jy);
4146 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4147 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4150 if (!IN_SCR_FIELD(sx, sy))
4153 /* ----------------------------------------------------------------------- */
4154 /* draw things behind the player, if needed */
4155 /* ----------------------------------------------------------------------- */
4158 DrawLevelElement(jx, jy, Back[jx][jy]);
4159 else if (IS_ACTIVE_BOMB(element))
4160 DrawLevelElement(jx, jy, EL_EMPTY);
4163 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4165 int old_element = GfxElement[jx][jy];
4166 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4167 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4169 if (GFX_CRUMBLED(old_element))
4170 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4172 DrawGraphic(sx, sy, old_graphic, frame);
4174 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4175 player_is_opaque = TRUE;
4179 GfxElement[jx][jy] = EL_UNDEFINED;
4181 /* make sure that pushed elements are drawn with correct frame rate */
4183 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4185 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4186 GfxFrame[jx][jy] = player->StepFrame;
4188 if (player->is_pushing && player->is_moving)
4189 GfxFrame[jx][jy] = player->StepFrame;
4192 DrawLevelField(jx, jy);
4196 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4197 /* ----------------------------------------------------------------------- */
4198 /* draw player himself */
4199 /* ----------------------------------------------------------------------- */
4201 graphic = getPlayerGraphic(player, move_dir);
4203 /* in the case of changed player action or direction, prevent the current
4204 animation frame from being restarted for identical animations */
4205 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4206 player->Frame = last_player_frame;
4208 frame = getGraphicAnimationFrame(graphic, player->Frame);
4212 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4213 sxx = player->GfxPos;
4215 syy = player->GfxPos;
4218 if (!setup.soft_scrolling && ScreenMovPos)
4221 if (player_is_opaque)
4222 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4224 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4226 if (SHIELD_ON(player))
4228 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4229 IMG_SHIELD_NORMAL_ACTIVE);
4230 int frame = getGraphicAnimationFrame(graphic, -1);
4232 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4236 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4239 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4240 sxx = player->GfxPos;
4242 syy = player->GfxPos;
4246 /* ----------------------------------------------------------------------- */
4247 /* draw things the player is pushing, if needed */
4248 /* ----------------------------------------------------------------------- */
4251 printf("::: %d, %d [%d, %d] [%d]\n",
4252 player->is_pushing, player_is_moving, player->GfxAction,
4253 player->is_moving, player_is_moving);
4257 if (player->is_pushing && player->is_moving)
4259 int px = SCREENX(jx), py = SCREENY(jy);
4260 int pxx = (TILEX - ABS(sxx)) * dx;
4261 int pyy = (TILEY - ABS(syy)) * dy;
4262 int gfx_frame = GfxFrame[jx][jy];
4268 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4270 element = Feld[next_jx][next_jy];
4271 gfx_frame = GfxFrame[next_jx][next_jy];
4274 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4277 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4278 frame = getGraphicAnimationFrame(graphic, sync_frame);
4280 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4283 /* draw background element under pushed element (like the Sokoban field) */
4285 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4287 /* this allows transparent pushing animation over non-black background */
4290 DrawLevelElement(jx, jy, Back[jx][jy]);
4292 DrawLevelElement(jx, jy, EL_EMPTY);
4294 if (Back[next_jx][next_jy])
4295 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4297 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4299 else if (Back[next_jx][next_jy])
4300 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4302 if (Back[next_jx][next_jy])
4303 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4307 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4308 jx, px, player->GfxPos, player->StepFrame,
4313 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4317 /* do not draw (EM style) pushing animation when pushing is finished */
4318 /* (two-tile animations usually do not contain start and end frame) */
4319 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4320 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4322 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4324 /* masked drawing is needed for EMC style (double) movement graphics */
4325 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4326 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4331 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4332 /* ----------------------------------------------------------------------- */
4333 /* draw player himself */
4334 /* ----------------------------------------------------------------------- */
4336 graphic = getPlayerGraphic(player, move_dir);
4338 /* in the case of changed player action or direction, prevent the current
4339 animation frame from being restarted for identical animations */
4340 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4341 player->Frame = last_player_frame;
4343 frame = getGraphicAnimationFrame(graphic, player->Frame);
4347 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4348 sxx = player->GfxPos;
4350 syy = player->GfxPos;
4353 if (!setup.soft_scrolling && ScreenMovPos)
4356 if (player_is_opaque)
4357 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4359 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4361 if (SHIELD_ON(player))
4363 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4364 IMG_SHIELD_NORMAL_ACTIVE);
4365 int frame = getGraphicAnimationFrame(graphic, -1);
4367 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4371 /* ----------------------------------------------------------------------- */
4372 /* draw things in front of player (active dynamite or dynabombs) */
4373 /* ----------------------------------------------------------------------- */
4375 if (IS_ACTIVE_BOMB(element))
4377 graphic = el2img(element);
4378 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4380 if (game.emulation == EMU_SUPAPLEX)
4381 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4383 DrawGraphicThruMask(sx, sy, graphic, frame);
4386 if (player_is_moving && last_element == EL_EXPLOSION)
4388 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4389 GfxElement[last_jx][last_jy] : EL_EMPTY);
4390 int graphic = el_act2img(element, ACTION_EXPLODING);
4391 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4392 int phase = ExplodePhase[last_jx][last_jy] - 1;
4393 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4396 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4399 /* ----------------------------------------------------------------------- */
4400 /* draw elements the player is just walking/passing through/under */
4401 /* ----------------------------------------------------------------------- */
4403 if (player_is_moving)
4405 /* handle the field the player is leaving ... */
4406 if (IS_ACCESSIBLE_INSIDE(last_element))
4407 DrawLevelField(last_jx, last_jy);
4408 else if (IS_ACCESSIBLE_UNDER(last_element))
4409 DrawLevelFieldThruMask(last_jx, last_jy);
4412 /* do not redraw accessible elements if the player is just pushing them */
4413 if (!player_is_moving || !player->is_pushing)
4415 /* ... and the field the player is entering */
4416 if (IS_ACCESSIBLE_INSIDE(element))
4417 DrawLevelField(jx, jy);
4418 else if (IS_ACCESSIBLE_UNDER(element))
4419 DrawLevelFieldThruMask(jx, jy);
4422 MarkTileDirty(sx, sy);
4425 /* ------------------------------------------------------------------------- */
4427 void WaitForEventToContinue()
4429 boolean still_wait = TRUE;
4431 /* simulate releasing mouse button over last gadget, if still pressed */
4433 HandleGadgets(-1, -1, 0);
4435 button_status = MB_RELEASED;
4451 case EVENT_BUTTONPRESS:
4452 case EVENT_KEYPRESS:
4456 case EVENT_KEYRELEASE:
4457 ClearPlayerAction();
4461 HandleOtherEvents(&event);
4465 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4472 /* don't eat all CPU time */
4477 #define MAX_REQUEST_LINES 13
4478 #define MAX_REQUEST_LINE_FONT1_LEN 7
4479 #define MAX_REQUEST_LINE_FONT2_LEN 10
4483 static int RequestHandleEvents(unsigned int req_state)
4485 int last_game_status = game_status; /* save current game status */
4489 button_status = MB_RELEASED;
4491 request_gadget_id = -1;
4504 case EVENT_BUTTONPRESS:
4505 case EVENT_BUTTONRELEASE:
4506 case EVENT_MOTIONNOTIFY:
4508 if (event.type == EVENT_MOTIONNOTIFY)
4510 if (!PointerInWindow(window))
4511 continue; /* window and pointer are on different screens */
4516 motion_status = TRUE;
4517 mx = ((MotionEvent *) &event)->x;
4518 my = ((MotionEvent *) &event)->y;
4522 motion_status = FALSE;
4523 mx = ((ButtonEvent *) &event)->x;
4524 my = ((ButtonEvent *) &event)->y;
4525 if (event.type == EVENT_BUTTONPRESS)
4526 button_status = ((ButtonEvent *) &event)->button;
4528 button_status = MB_RELEASED;
4531 /* this sets 'request_gadget_id' */
4532 HandleGadgets(mx, my, button_status);
4534 switch (request_gadget_id)
4536 case TOOL_CTRL_ID_YES:
4539 case TOOL_CTRL_ID_NO:
4542 case TOOL_CTRL_ID_CONFIRM:
4543 result = TRUE | FALSE;
4546 case TOOL_CTRL_ID_PLAYER_1:
4549 case TOOL_CTRL_ID_PLAYER_2:
4552 case TOOL_CTRL_ID_PLAYER_3:
4555 case TOOL_CTRL_ID_PLAYER_4:
4566 case EVENT_KEYPRESS:
4567 switch (GetEventKey((KeyEvent *)&event, TRUE))
4570 if (req_state & REQ_CONFIRM)
4579 #if defined(TARGET_SDL2)
4589 if (req_state & REQ_PLAYER)
4593 case EVENT_KEYRELEASE:
4594 ClearPlayerAction();
4598 HandleOtherEvents(&event);
4602 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4604 int joy = AnyJoystick();
4606 if (joy & JOY_BUTTON_1)
4608 else if (joy & JOY_BUTTON_2)
4614 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4616 HandleGameActions();
4622 if (!PendingEvent()) /* delay only if no pending events */
4627 game_status = GAME_MODE_PSEUDO_DOOR;
4633 game_status = last_game_status; /* restore current game status */
4641 if (!PendingEvent()) /* delay only if no pending events */
4644 /* don't eat all CPU time */
4654 static boolean RequestDoor(char *text, unsigned int req_state)
4656 unsigned int old_door_state;
4657 int last_game_status = game_status; /* save current game status */
4658 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4659 int font_nr = FONT_TEXT_2;
4664 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4666 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4667 font_nr = FONT_TEXT_1;
4670 if (game_status == GAME_MODE_PLAYING)
4673 BlitScreenToBitmap(backbuffer);
4675 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4676 BlitScreenToBitmap_EM(backbuffer);
4677 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4678 BlitScreenToBitmap_SP(backbuffer);
4682 /* disable deactivated drawing when quick-loading level tape recording */
4683 if (tape.playing && tape.deactivate_display)
4684 TapeDeactivateDisplayOff(TRUE);
4686 SetMouseCursor(CURSOR_DEFAULT);
4688 #if defined(NETWORK_AVALIABLE)
4689 /* pause network game while waiting for request to answer */
4690 if (options.network &&
4691 game_status == GAME_MODE_PLAYING &&
4692 req_state & REQUEST_WAIT_FOR_INPUT)
4693 SendToServer_PausePlaying();
4696 old_door_state = GetDoorState();
4698 /* simulate releasing mouse button over last gadget, if still pressed */
4700 HandleGadgets(-1, -1, 0);
4704 /* draw released gadget before proceeding */
4707 if (old_door_state & DOOR_OPEN_1)
4709 CloseDoor(DOOR_CLOSE_1);
4711 /* save old door content */
4713 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4714 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4716 BlitBitmap(bitmap_db_door, bitmap_db_door,
4717 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4718 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4722 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4723 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4725 /* clear door drawing field */
4726 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4728 /* force DOOR font inside door area */
4729 game_status = GAME_MODE_PSEUDO_DOOR;
4731 /* write text for request */
4732 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4734 char text_line[max_request_line_len + 1];
4740 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4742 tc = *(text_ptr + tx);
4743 // if (!tc || tc == ' ')
4744 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4748 if ((tc == '?' || tc == '!') && tl == 0)
4758 strncpy(text_line, text_ptr, tl);
4761 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4762 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4763 text_line, font_nr);
4765 text_ptr += tl + (tc == ' ' ? 1 : 0);
4766 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4769 game_status = last_game_status; /* restore current game status */
4771 if (req_state & REQ_ASK)
4773 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4774 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4776 else if (req_state & REQ_CONFIRM)
4778 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4780 else if (req_state & REQ_PLAYER)
4782 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4783 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4784 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4785 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4788 /* copy request gadgets to door backbuffer */
4790 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4792 BlitBitmap(drawto, bitmap_db_door,
4793 DX, DY, DXSIZE, DYSIZE,
4794 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4797 OpenDoor(DOOR_OPEN_1);
4799 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4801 if (game_status == GAME_MODE_PLAYING)
4803 SetPanelBackground();
4804 SetDrawBackgroundMask(REDRAW_DOOR_1);
4808 SetDrawBackgroundMask(REDRAW_FIELD);
4814 if (game_status != GAME_MODE_MAIN)
4817 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4819 // ---------- handle request buttons ----------
4820 result = RequestHandleEvents(req_state);
4822 if (game_status != GAME_MODE_MAIN)
4827 if (!(req_state & REQ_STAY_OPEN))
4829 CloseDoor(DOOR_CLOSE_1);
4831 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4832 (req_state & REQ_REOPEN))
4833 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4838 if (game_status == GAME_MODE_PLAYING)
4840 SetPanelBackground();
4841 SetDrawBackgroundMask(REDRAW_DOOR_1);
4845 SetDrawBackgroundMask(REDRAW_FIELD);
4848 #if defined(NETWORK_AVALIABLE)
4849 /* continue network game after request */
4850 if (options.network &&
4851 game_status == GAME_MODE_PLAYING &&
4852 req_state & REQUEST_WAIT_FOR_INPUT)
4853 SendToServer_ContinuePlaying();
4856 /* restore deactivated drawing when quick-loading level tape recording */
4857 if (tape.playing && tape.deactivate_display)
4858 TapeDeactivateDisplayOn();
4863 static boolean RequestEnvelope(char *text, unsigned int req_state)
4870 if (game_status == GAME_MODE_PLAYING)
4874 BlitScreenToBitmap(backbuffer);
4876 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4877 BlitScreenToBitmap_EM(backbuffer);
4878 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4879 BlitScreenToBitmap_SP(backbuffer);
4881 BlitScreenToBitmap_RND(backbuffer);
4884 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4885 BlitScreenToBitmap_EM(backbuffer);
4886 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4887 BlitScreenToBitmap_SP(backbuffer);
4891 /* disable deactivated drawing when quick-loading level tape recording */
4892 if (tape.playing && tape.deactivate_display)
4893 TapeDeactivateDisplayOff(TRUE);
4895 SetMouseCursor(CURSOR_DEFAULT);
4897 #if defined(NETWORK_AVALIABLE)
4898 /* pause network game while waiting for request to answer */
4899 if (options.network &&
4900 game_status == GAME_MODE_PLAYING &&
4901 req_state & REQUEST_WAIT_FOR_INPUT)
4902 SendToServer_PausePlaying();
4905 /* simulate releasing mouse button over last gadget, if still pressed */
4907 HandleGadgets(-1, -1, 0);
4911 // (replace with setting corresponding request background)
4912 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4913 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4915 /* clear door drawing field */
4916 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4919 if (global.use_envelope_request)
4923 CreateToolButtons();
4929 if (req_state & REQ_ASK)
4931 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4932 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4934 else if (req_state & REQ_CONFIRM)
4936 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4938 else if (req_state & REQ_PLAYER)
4940 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4941 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4942 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4943 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4946 if (req_state & REQ_ASK)
4948 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4949 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4951 else if (req_state & REQ_CONFIRM)
4953 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4955 else if (req_state & REQ_PLAYER)
4957 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4958 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4959 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4960 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4965 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4968 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4970 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4971 i == TOOL_CTRL_ID_NO)) ||
4972 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4973 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4974 i == TOOL_CTRL_ID_PLAYER_2 &&
4975 i == TOOL_CTRL_ID_PLAYER_3 &&
4976 i == TOOL_CTRL_ID_PLAYER_4)))
4978 int x = tool_gadget[i]->x + dDX;
4979 int y = tool_gadget[i]->y + dDY;
4981 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4986 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4988 if (game_status == GAME_MODE_PLAYING)
4990 SetPanelBackground();
4991 SetDrawBackgroundMask(REDRAW_DOOR_1);
4995 SetDrawBackgroundMask(REDRAW_FIELD);
5002 if (game_status != GAME_MODE_MAIN)
5006 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5008 // ---------- handle request buttons ----------
5009 result = RequestHandleEvents(req_state);
5011 if (game_status != GAME_MODE_MAIN)
5016 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5020 if (game_status == GAME_MODE_PLAYING)
5022 SetPanelBackground();
5023 SetDrawBackgroundMask(REDRAW_DOOR_1);
5027 SetDrawBackgroundMask(REDRAW_FIELD);
5030 #if defined(NETWORK_AVALIABLE)
5031 /* continue network game after request */
5032 if (options.network &&
5033 game_status == GAME_MODE_PLAYING &&
5034 req_state & REQUEST_WAIT_FOR_INPUT)
5035 SendToServer_ContinuePlaying();
5038 /* restore deactivated drawing when quick-loading level tape recording */
5039 if (tape.playing && tape.deactivate_display)
5040 TapeDeactivateDisplayOn();
5045 boolean Request(char *text, unsigned int req_state)
5047 if (global.use_envelope_request)
5048 return RequestEnvelope(text, req_state);
5050 return RequestDoor(text, req_state);
5053 #else // =====================================================================
5055 boolean Request(char *text, unsigned int req_state)
5057 int mx, my, ty, result = -1;
5058 unsigned int old_door_state;
5059 int last_game_status = game_status; /* save current game status */
5060 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5061 int font_nr = FONT_TEXT_2;
5063 int max_word_len = 0;
5069 global.use_envelope_request = 1;
5073 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5075 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5076 font_nr = FONT_TEXT_1;
5079 for (text_ptr = text; *text_ptr; text_ptr++)
5081 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5083 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5085 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5087 font_nr = FONT_TEXT_1;
5089 font_nr = FONT_LEVEL_NUMBER;
5097 if (game_status == GAME_MODE_PLAYING)
5100 BlitScreenToBitmap(backbuffer);
5102 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5103 BlitScreenToBitmap_EM(backbuffer);
5104 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5105 BlitScreenToBitmap_SP(backbuffer);
5109 /* disable deactivated drawing when quick-loading level tape recording */
5110 if (tape.playing && tape.deactivate_display)
5111 TapeDeactivateDisplayOff(TRUE);
5113 SetMouseCursor(CURSOR_DEFAULT);
5115 #if defined(NETWORK_AVALIABLE)
5116 /* pause network game while waiting for request to answer */
5117 if (options.network &&
5118 game_status == GAME_MODE_PLAYING &&
5119 req_state & REQUEST_WAIT_FOR_INPUT)
5120 SendToServer_PausePlaying();
5123 old_door_state = GetDoorState();
5125 /* simulate releasing mouse button over last gadget, if still pressed */
5127 HandleGadgets(-1, -1, 0);
5131 /* draw released gadget before proceeding */
5135 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5137 if (old_door_state & DOOR_OPEN_1)
5141 if (!global.use_envelope_request)
5142 CloseDoor(DOOR_CLOSE_1);
5144 CloseDoor(DOOR_CLOSE_1);
5147 /* save old door content */
5148 BlitBitmap(bitmap_db_door, bitmap_db_door,
5149 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5150 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5154 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5157 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5159 /* clear door drawing field */
5160 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5162 /* force DOOR font inside door area */
5163 game_status = GAME_MODE_PSEUDO_DOOR;
5165 /* write text for request */
5166 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5168 char text_line[max_request_line_len + 1];
5174 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5176 tc = *(text_ptr + tx);
5177 if (!tc || tc == ' ')
5188 strncpy(text_line, text_ptr, tl);
5191 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5192 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5193 text_line, font_nr);
5195 text_ptr += tl + (tc == ' ' ? 1 : 0);
5198 game_status = last_game_status; /* restore current game status */
5201 if (global.use_envelope_request)
5205 CreateToolButtons();
5209 if (req_state & REQ_ASK)
5211 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5212 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5214 else if (req_state & REQ_CONFIRM)
5216 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5218 else if (req_state & REQ_PLAYER)
5220 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5221 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5222 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5223 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5226 /* copy request gadgets to door backbuffer */
5227 BlitBitmap(drawto, bitmap_db_door,
5228 DX, DY, DXSIZE, DYSIZE,
5229 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5232 if (global.use_envelope_request)
5234 ShowEnvelopeRequest(text, ACTION_OPENING);
5236 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5238 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5239 i == TOOL_CTRL_ID_NO)) ||
5240 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5241 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5242 i == TOOL_CTRL_ID_PLAYER_2 &&
5243 i == TOOL_CTRL_ID_PLAYER_3 &&
5244 i == TOOL_CTRL_ID_PLAYER_4)))
5246 int x = tool_gadget[i]->x + dDX;
5247 int y = tool_gadget[i]->y + dDY;
5249 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5256 if (!global.use_envelope_request)
5257 OpenDoor(DOOR_OPEN_1);
5259 OpenDoor(DOOR_OPEN_1);
5262 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5264 if (game_status == GAME_MODE_PLAYING)
5266 SetPanelBackground();
5267 SetDrawBackgroundMask(REDRAW_DOOR_1);
5271 SetDrawBackgroundMask(REDRAW_FIELD);
5278 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5281 if (game_status != GAME_MODE_MAIN)
5285 button_status = MB_RELEASED;
5287 request_gadget_id = -1;
5289 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5301 case EVENT_BUTTONPRESS:
5302 case EVENT_BUTTONRELEASE:
5303 case EVENT_MOTIONNOTIFY:
5305 if (event.type == EVENT_MOTIONNOTIFY)
5307 if (!PointerInWindow(window))
5308 continue; /* window and pointer are on different screens */
5313 motion_status = TRUE;
5314 mx = ((MotionEvent *) &event)->x;
5315 my = ((MotionEvent *) &event)->y;
5319 motion_status = FALSE;
5320 mx = ((ButtonEvent *) &event)->x;
5321 my = ((ButtonEvent *) &event)->y;
5322 if (event.type == EVENT_BUTTONPRESS)
5323 button_status = ((ButtonEvent *) &event)->button;
5325 button_status = MB_RELEASED;
5328 /* this sets 'request_gadget_id' */
5329 HandleGadgets(mx, my, button_status);
5331 switch (request_gadget_id)
5333 case TOOL_CTRL_ID_YES:
5336 case TOOL_CTRL_ID_NO:
5339 case TOOL_CTRL_ID_CONFIRM:
5340 result = TRUE | FALSE;
5343 case TOOL_CTRL_ID_PLAYER_1:
5346 case TOOL_CTRL_ID_PLAYER_2:
5349 case TOOL_CTRL_ID_PLAYER_3:
5352 case TOOL_CTRL_ID_PLAYER_4:
5363 case EVENT_KEYPRESS:
5364 switch (GetEventKey((KeyEvent *)&event, TRUE))
5367 if (req_state & REQ_CONFIRM)
5376 #if defined(TARGET_SDL2)
5386 if (req_state & REQ_PLAYER)
5390 case EVENT_KEYRELEASE:
5391 ClearPlayerAction();
5395 HandleOtherEvents(&event);
5399 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5401 int joy = AnyJoystick();
5403 if (joy & JOY_BUTTON_1)
5405 else if (joy & JOY_BUTTON_2)
5411 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5413 HandleGameActions();
5419 if (!PendingEvent()) /* delay only if no pending events */
5424 game_status = GAME_MODE_PSEUDO_DOOR;
5430 game_status = last_game_status; /* restore current game status */
5438 if (!PendingEvent()) /* delay only if no pending events */
5441 /* don't eat all CPU time */
5448 if (game_status != GAME_MODE_MAIN)
5454 if (global.use_envelope_request)
5455 ShowEnvelopeRequest(text, ACTION_CLOSING);
5459 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5461 if (!(req_state & REQ_STAY_OPEN))
5464 CloseDoor(DOOR_CLOSE_1);
5466 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5467 (req_state & REQ_REOPEN))
5468 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5473 if (game_status == GAME_MODE_PLAYING)
5475 SetPanelBackground();
5476 SetDrawBackgroundMask(REDRAW_DOOR_1);
5480 SetDrawBackgroundMask(REDRAW_FIELD);
5483 #if defined(NETWORK_AVALIABLE)
5484 /* continue network game after request */
5485 if (options.network &&
5486 game_status == GAME_MODE_PLAYING &&
5487 req_state & REQUEST_WAIT_FOR_INPUT)
5488 SendToServer_ContinuePlaying();
5491 /* restore deactivated drawing when quick-loading level tape recording */
5492 if (tape.playing && tape.deactivate_display)
5493 TapeDeactivateDisplayOn();
5500 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5502 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5503 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5506 if (dpo1->sort_priority != dpo2->sort_priority)
5507 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5509 compare_result = dpo1->nr - dpo2->nr;
5511 return compare_result;
5514 void InitGraphicCompatibilityInfo_Doors()
5520 struct DoorInfo *door;
5524 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5525 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5527 { -1, -1, -1, NULL }
5529 struct Rect door_rect_list[] =
5531 { DX, DY, DXSIZE, DYSIZE },
5532 { VX, VY, VXSIZE, VYSIZE }
5536 for (i = 0; doors[i].door_token != -1; i++)
5538 int door_token = doors[i].door_token;
5539 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5540 int part_1 = doors[i].part_1;
5541 int part_8 = doors[i].part_8;
5542 int part_2 = part_1 + 1;
5543 int part_3 = part_1 + 2;
5544 struct DoorInfo *door = doors[i].door;
5545 struct Rect *door_rect = &door_rect_list[door_index];
5546 boolean door_gfx_redefined = FALSE;
5548 /* check if any door part graphic definitions have been redefined */
5550 for (j = 0; door_part_controls[j].door_token != -1; j++)
5552 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5553 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5555 if (dpc->door_token == door_token && fi->redefined)
5556 door_gfx_redefined = TRUE;
5559 /* check for old-style door graphic/animation modifications */
5561 if (!door_gfx_redefined)
5563 if (door->anim_mode & ANIM_STATIC_PANEL)
5565 door->panel.step_xoffset = 0;
5566 door->panel.step_yoffset = 0;
5569 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5571 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5572 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5573 int num_door_steps, num_panel_steps;
5575 /* remove door part graphics other than the two default wings */
5577 for (j = 0; door_part_controls[j].door_token != -1; j++)
5579 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5580 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5582 if (dpc->graphic >= part_3 &&
5583 dpc->graphic <= part_8)
5587 /* set graphics and screen positions of the default wings */
5589 g_part_1->width = door_rect->width;
5590 g_part_1->height = door_rect->height;
5591 g_part_2->width = door_rect->width;
5592 g_part_2->height = door_rect->height;
5593 g_part_2->src_x = door_rect->width;
5594 g_part_2->src_y = g_part_1->src_y;
5596 door->part_2.x = door->part_1.x;
5597 door->part_2.y = door->part_1.y;
5599 if (door->width != -1)
5601 g_part_1->width = door->width;
5602 g_part_2->width = door->width;
5604 // special treatment for graphics and screen position of right wing
5605 g_part_2->src_x += door_rect->width - door->width;
5606 door->part_2.x += door_rect->width - door->width;
5609 if (door->height != -1)
5611 g_part_1->height = door->height;
5612 g_part_2->height = door->height;
5614 // special treatment for graphics and screen position of bottom wing
5615 g_part_2->src_y += door_rect->height - door->height;
5616 door->part_2.y += door_rect->height - door->height;
5619 /* set animation delays for the default wings and panels */
5621 door->part_1.step_delay = door->step_delay;
5622 door->part_2.step_delay = door->step_delay;
5623 door->panel.step_delay = door->step_delay;
5625 /* set animation draw order for the default wings */
5627 door->part_1.sort_priority = 2; /* draw left wing over ... */
5628 door->part_2.sort_priority = 1; /* ... right wing */
5630 /* set animation draw offset for the default wings */
5632 if (door->anim_mode & ANIM_HORIZONTAL)
5634 door->part_1.step_xoffset = door->step_offset;
5635 door->part_1.step_yoffset = 0;
5636 door->part_2.step_xoffset = door->step_offset * -1;
5637 door->part_2.step_yoffset = 0;
5639 num_door_steps = g_part_1->width / door->step_offset;
5641 else // ANIM_VERTICAL
5643 door->part_1.step_xoffset = 0;
5644 door->part_1.step_yoffset = door->step_offset;
5645 door->part_2.step_xoffset = 0;
5646 door->part_2.step_yoffset = door->step_offset * -1;
5648 num_door_steps = g_part_1->height / door->step_offset;
5651 /* set animation draw offset for the default panels */
5653 if (door->step_offset > 1)
5655 num_panel_steps = 2 * door_rect->height / door->step_offset;
5656 door->panel.start_step = num_panel_steps - num_door_steps;
5660 num_panel_steps = door_rect->height / door->step_offset;
5661 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5662 door->panel.step_delay *= 2;
5673 for (i = 0; door_part_controls[i].door_token != -1; i++)
5675 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5676 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5678 /* initialize "start_step_opening" and "start_step_closing", if needed */
5679 if (dpc->pos->start_step_opening == 0 &&
5680 dpc->pos->start_step_closing == 0)
5682 // dpc->pos->start_step_opening = dpc->pos->start_step;
5683 dpc->pos->start_step_closing = dpc->pos->start_step;
5686 /* fill structure for door part draw order (sorted below) */
5688 dpo->sort_priority = dpc->pos->sort_priority;
5691 struct DoorPartPosInfo *pos = dpc->pos;
5693 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5694 pos->step_xoffset, pos->step_yoffset);
5698 /* sort door part controls according to sort_priority and graphic number */
5699 qsort(door_part_order, MAX_DOOR_PARTS,
5700 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5703 unsigned int OpenDoor(unsigned int door_state)
5705 if (door_state & DOOR_COPY_BACK)
5708 if (door_state & DOOR_OPEN_1)
5709 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5710 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5712 if (door_state & DOOR_OPEN_2)
5713 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5714 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5716 if (door_state & DOOR_OPEN_1)
5717 BlitBitmap(bitmap_db_door, bitmap_db_door,
5718 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5719 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5721 if (door_state & DOOR_OPEN_2)
5722 BlitBitmap(bitmap_db_door, bitmap_db_door,
5723 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5724 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5727 door_state &= ~DOOR_COPY_BACK;
5730 return MoveDoor(door_state);
5733 unsigned int CloseDoor(unsigned int door_state)
5735 unsigned int old_door_state = GetDoorState();
5737 if (!(door_state & DOOR_NO_COPY_BACK))
5740 if (old_door_state & DOOR_OPEN_1)
5741 BlitBitmap(backbuffer, bitmap_db_door_1,
5742 DX, DY, DXSIZE, DYSIZE, 0, 0);
5744 if (old_door_state & DOOR_OPEN_2)
5745 BlitBitmap(backbuffer, bitmap_db_door_2,
5746 VX, VY, VXSIZE, VYSIZE, 0, 0);
5748 if (old_door_state & DOOR_OPEN_1)
5749 BlitBitmap(backbuffer, bitmap_db_door,
5750 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5752 if (old_door_state & DOOR_OPEN_2)
5753 BlitBitmap(backbuffer, bitmap_db_door,
5754 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5757 door_state &= ~DOOR_NO_COPY_BACK;
5760 return MoveDoor(door_state);
5763 unsigned int GetDoorState()
5765 return MoveDoor(DOOR_GET_STATE);
5768 unsigned int SetDoorState(unsigned int door_state)
5770 return MoveDoor(door_state | DOOR_SET_STATE);
5775 // ========== TEST 1 ===========================================================
5777 int euclid(int a, int b)
5779 return (b ? euclid(b, a % b) : a);
5782 unsigned int MoveDoor(unsigned int door_state)
5785 struct XY panel_pos_list[] =
5787 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5788 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5791 struct Rect door_rect_list[] =
5793 { DX, DY, DXSIZE, DYSIZE },
5794 { VX, VY, VXSIZE, VYSIZE }
5796 static int door1 = DOOR_OPEN_1;
5797 static int door2 = DOOR_CLOSE_2;
5798 unsigned int door_delay = 0;
5799 unsigned int door_delay_value;
5803 if (door_1.width < 0 || door_1.width > DXSIZE)
5804 door_1.width = DXSIZE;
5805 if (door_1.height < 0 || door_1.height > DYSIZE)
5806 door_1.height = DYSIZE;
5807 if (door_2.width < 0 || door_2.width > VXSIZE)
5808 door_2.width = VXSIZE;
5809 if (door_2.height < 0 || door_2.height > VYSIZE)
5810 door_2.height = VYSIZE;
5813 if (door_state == DOOR_GET_STATE)
5814 return (door1 | door2);
5816 if (door_state & DOOR_SET_STATE)
5818 if (door_state & DOOR_ACTION_1)
5819 door1 = door_state & DOOR_ACTION_1;
5820 if (door_state & DOOR_ACTION_2)
5821 door2 = door_state & DOOR_ACTION_2;
5823 return (door1 | door2);
5826 if (!(door_state & DOOR_FORCE_REDRAW))
5828 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5829 door_state &= ~DOOR_OPEN_1;
5830 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5831 door_state &= ~DOOR_CLOSE_1;
5832 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5833 door_state &= ~DOOR_OPEN_2;
5834 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5835 door_state &= ~DOOR_CLOSE_2;
5839 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5842 if (setup.quick_doors)
5844 stepsize = 20; /* must be chosen to always draw last frame */
5845 door_delay_value = 0;
5849 if (global.autoplay_leveldir)
5851 door_state |= DOOR_NO_DELAY;
5852 door_state &= ~DOOR_CLOSE_ALL;
5856 if (game_status == GAME_MODE_EDITOR)
5857 door_state |= DOOR_NO_DELAY;
5860 if (door_state & DOOR_ACTION)
5862 boolean door_panel_drawn[NUM_DOORS];
5863 boolean panel_has_doors[NUM_DOORS];
5864 boolean door_part_skip[MAX_DOOR_PARTS];
5865 boolean door_part_done[MAX_DOOR_PARTS];
5866 boolean door_part_done_all;
5867 int num_steps[MAX_DOOR_PARTS];
5868 int max_move_delay = 0; // delay for complete animations of all doors
5869 int max_step_delay = 0; // delay (ms) between two animation frames
5870 int num_move_steps = 0; // number of animation steps for all doors
5871 int current_move_delay = 0;
5874 for (i = 0; i < NUM_DOORS; i++)
5875 panel_has_doors[i] = FALSE;
5877 for (i = 0; i < MAX_DOOR_PARTS; i++)
5879 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5880 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5881 int door_token = dpc->door_token;
5883 door_part_done[i] = FALSE;
5884 door_part_skip[i] = (!(door_state & door_token) ||
5889 for (i = 0; i < MAX_DOOR_PARTS; i++)
5891 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5892 struct DoorPartPosInfo *pos = dpc->pos;
5893 int start_step = pos->start_step;
5895 printf("::: ---> %d: start_step == %d [%d]\n",
5896 i, start_step, door_part_done[i]);
5900 for (i = 0; i < MAX_DOOR_PARTS; i++)
5902 int nr = door_part_order[i].nr;
5903 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5904 struct DoorPartPosInfo *pos = dpc->pos;
5905 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5906 int door_token = dpc->door_token;
5907 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5908 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5909 int step_xoffset = ABS(pos->step_xoffset);
5910 int step_yoffset = ABS(pos->step_yoffset);
5911 int step_delay = pos->step_delay;
5912 int current_door_state = door_state & door_token;
5913 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5914 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5915 boolean part_opening = (is_panel ? door_closing : door_opening);
5916 int start_step = (part_opening ? pos->start_step_opening :
5917 pos->start_step_closing);
5918 float move_xsize = (step_xoffset ? g->width : 0);
5919 float move_ysize = (step_yoffset ? g->height : 0);
5920 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5921 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5922 int move_steps = (move_xsteps && move_ysteps ?
5923 MIN(move_xsteps, move_ysteps) :
5924 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5925 int move_delay = move_steps * step_delay;
5927 if (door_part_skip[nr])
5931 panel_has_doors[door_index] = TRUE;
5933 max_move_delay = MAX(max_move_delay, move_delay);
5934 max_step_delay = (max_step_delay == 0 ? step_delay :
5935 euclid(max_step_delay, step_delay));
5936 num_steps[nr] = move_steps;
5940 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5941 i, move_delay, start_step, door_part_order[i].nr);
5943 if (DOOR_PART_IS_PANEL(i))
5944 printf("::: %d: move_delay == %d, start_step == %d\n",
5945 i, move_delay, start_step);
5950 num_move_steps = max_move_delay / max_step_delay;
5952 door_delay_value = max_step_delay;
5955 door_delay_value *= 10;
5959 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5962 for (k = 0; k < num_move_steps; k++)
5964 door_part_done_all = TRUE;
5966 for (i = 0; i < NUM_DOORS; i++)
5967 door_panel_drawn[i] = FALSE;
5969 for (i = 0; i < MAX_DOOR_PARTS; i++)
5971 int nr = door_part_order[i].nr;
5972 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5973 struct DoorPartPosInfo *pos = dpc->pos;
5974 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5975 int door_token = dpc->door_token;
5976 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5977 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5979 struct XY *panel_pos = &panel_pos_list[door_index];
5981 struct Rect *door_rect = &door_rect_list[door_index];
5982 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5984 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5985 int current_door_state = door_state & door_token;
5986 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5987 boolean door_closing = !door_opening;
5988 boolean part_opening = (is_panel ? door_closing : door_opening);
5989 boolean part_closing = !part_opening;
5990 int start_step = (part_opening ? pos->start_step_opening :
5991 pos->start_step_closing);
5992 int step_delay = pos->step_delay;
5993 int step_factor = step_delay / max_step_delay;
5994 int k1 = (step_factor ? k / step_factor + 1 : k);
5995 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5996 int kk = (k2 < 0 ? 0 : k2);
5997 int src_x, src_y, src_xx, src_yy;
5998 int dst_x, dst_y, dst_xx, dst_yy;
6002 if (k == 0 && is_panel && door_token == DOOR_2)
6003 printf("::: %d, %d\n", g->width, g->height);
6007 if (DOOR_PART_IS_PANEL(nr))
6009 int start_step = pos->start_step;
6011 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6012 kk = (k2 < 0 ? 0 : k2);
6018 if (nr != 16 && nr != 0)
6029 if (door_part_skip[nr])
6033 if (!(door_state & door_token))
6040 if (current_move_delay % step_delay)
6046 if (!door_panel_drawn[door_index])
6049 ClearRectangle(drawto, door_rect->x, door_rect->y,
6050 door_rect->width, door_rect->height);
6052 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6053 door_rect->width, door_rect->height,
6054 door_rect->x, door_rect->y);
6057 door_panel_drawn[door_index] = TRUE;
6060 // draw opening or closing door parts
6062 if (pos->step_xoffset < 0) // door part on right side
6065 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6068 if (dst_xx + width > door_rect->width)
6069 width = door_rect->width - dst_xx;
6071 else // door part on left side
6074 dst_xx = pos->x - kk * pos->step_xoffset;
6078 src_xx = ABS(dst_xx);
6082 width = g->width - src_xx;
6084 // printf("::: k == %d [%d] \n", k, start_step);
6087 if (pos->step_yoffset < 0) // door part on bottom side
6090 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6093 if (dst_yy + height > door_rect->height)
6094 height = door_rect->height - dst_yy;
6096 else // door part on top side
6099 dst_yy = pos->y - kk * pos->step_yoffset;
6103 src_yy = ABS(dst_yy);
6107 height = g->height - src_yy;
6116 src_x = panel_pos->x + src_xx;
6117 src_y = panel_pos->y + src_yy;
6122 src_x = g->src_x + src_xx;
6123 src_y = g->src_y + src_yy;
6126 dst_x = door_rect->x + dst_xx;
6127 dst_y = door_rect->y + dst_yy;
6130 if (DOOR_PART_IS_PANEL(nr))
6132 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6133 width, height, g->width, g->height, src_x, src_y);
6137 if (width >= 0 && width <= g->width &&
6138 height >= 0 && height <= g->height)
6140 if (is_panel || !pos->draw_masked)
6141 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6144 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6149 if (DOOR_PART_IS_PANEL(nr))
6151 bitmap = bitmap_db_door;
6152 src_x = panel_pos->x + src_xx;
6153 src_y = panel_pos->y + src_yy;
6155 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6156 width, height, g->width, g->height, src_x, src_y);
6158 if (width >= 0 && width <= g->width &&
6159 height >= 0 && height <= g->height)
6160 BlitBitmap(bitmap, drawto, src_x, src_y,
6166 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6169 if ((part_opening && (width < 0 || height < 0)) ||
6170 (part_closing && (width >= g->width && height >= g->height)))
6171 door_part_done[nr] = TRUE;
6173 if ((door_opening && (width < 0 || height < 0)) ||
6174 (door_closing && (width >= g->width && height >= g->height)))
6175 door_part_done[nr] = TRUE;
6179 // continue door part animations, but not panel after door has closed
6180 if (!door_part_done[nr] &&
6181 !(is_panel && door_closing && panel_has_doors[door_index]))
6182 door_part_done_all = FALSE;
6184 // continue door part animations, but not panel after door has closed
6185 if (!door_part_done[nr] && !(is_panel && door_closing))
6186 door_part_done_all = FALSE;
6190 if (!door_part_done[nr])
6191 printf("::: k == %d, nr == %d\n", k, nr);
6195 if (!(door_state & DOOR_NO_DELAY))
6199 if (game_status == GAME_MODE_MAIN)
6202 WaitUntilDelayReached(&door_delay, door_delay_value);
6204 current_move_delay += max_step_delay;
6208 door_part_done_all = TRUE;
6210 for (i = 0; i < MAX_DOOR_PARTS; i++)
6211 if (!door_part_done[i] &&
6212 !(DOOR_PART_IS_PANEL(i) && door_closing))
6213 door_part_done_all = FALSE;
6216 if (door_part_done_all)
6222 if (door_state & DOOR_ACTION_1)
6223 door1 = door_state & DOOR_ACTION_1;
6224 if (door_state & DOOR_ACTION_2)
6225 door2 = door_state & DOOR_ACTION_2;
6228 printf("::: DOORS DONE %08x\n", door_state);
6230 printf("::: GO!\n");
6233 return (door1 | door2);
6238 // ========== OLD ==============================================================
6240 unsigned int MoveDoor(unsigned int door_state)
6242 static int door1 = DOOR_OPEN_1;
6243 static int door2 = DOOR_CLOSE_2;
6244 unsigned int door_delay = 0;
6245 unsigned int door_delay_value;
6249 if (door_1.width < 0 || door_1.width > DXSIZE)
6250 door_1.width = DXSIZE;
6251 if (door_1.height < 0 || door_1.height > DYSIZE)
6252 door_1.height = DYSIZE;
6253 if (door_2.width < 0 || door_2.width > VXSIZE)
6254 door_2.width = VXSIZE;
6255 if (door_2.height < 0 || door_2.height > VYSIZE)
6256 door_2.height = VYSIZE;
6259 if (door_state == DOOR_GET_STATE)
6260 return (door1 | door2);
6262 if (door_state & DOOR_SET_STATE)
6264 if (door_state & DOOR_ACTION_1)
6265 door1 = door_state & DOOR_ACTION_1;
6266 if (door_state & DOOR_ACTION_2)
6267 door2 = door_state & DOOR_ACTION_2;
6269 return (door1 | door2);
6272 if (!(door_state & DOOR_FORCE_REDRAW))
6274 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6275 door_state &= ~DOOR_OPEN_1;
6276 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6277 door_state &= ~DOOR_CLOSE_1;
6278 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6279 door_state &= ~DOOR_OPEN_2;
6280 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6281 door_state &= ~DOOR_CLOSE_2;
6284 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6287 // door_delay_value *= 4; // !!! TEST ONLY !!!
6289 if (setup.quick_doors)
6291 stepsize = 20; /* must be chosen to always draw last frame */
6292 door_delay_value = 0;
6295 if (global.autoplay_leveldir)
6297 door_state |= DOOR_NO_DELAY;
6298 door_state &= ~DOOR_CLOSE_ALL;
6302 if (game_status == GAME_MODE_EDITOR)
6303 door_state |= DOOR_NO_DELAY;
6306 if (door_state & DOOR_ACTION)
6309 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6310 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6311 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6312 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6313 int door_1_left_width = g1_left->width;
6314 int door_1_left_height = g1_left->height;
6315 int door_1_right_width = g1_right->width;
6316 int door_1_right_height = g1_right->height;
6317 int door_2_left_width = g2_left->width;
6318 int door_2_left_height = g2_left->height;
6319 int door_2_right_width = g2_right->width;
6320 int door_2_right_height = g2_right->height;
6321 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6322 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6323 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6324 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6326 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6327 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6328 boolean door_1_done = (!handle_door_1);
6329 boolean door_2_done = (!handle_door_2);
6330 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6331 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6334 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6335 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6337 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6338 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6341 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6342 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6344 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6345 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6346 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6347 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6348 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6349 int door_skip = max_door_size - door_size;
6350 int end = door_size;
6351 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6354 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6356 /* opening door sound has priority over simultaneously closing door */
6357 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6358 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6359 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6360 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6363 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6367 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6368 GC gc = bitmap->stored_clip_gc;
6371 if (door_state & DOOR_ACTION_1 &&
6372 x * door_1.step_offset <= door_size_1)
6374 int a = MIN(x * door_1.step_offset, end);
6375 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6379 int i = p + door_skip;
6383 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6384 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6385 Bitmap *bm_left = g_left->bitmap;
6386 Bitmap *bm_right = g_right->bitmap;
6387 GC gc_left = bm_left->stored_clip_gc;
6388 GC gc_right = bm_right->stored_clip_gc;
6391 int classic_dxsize = 100;
6392 int classic_dysize = 280;
6393 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6394 DYSIZE == classic_dysize);
6396 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6398 BlitBitmap(bitmap_db_door, drawto,
6399 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6400 DXSIZE, DYSIZE, DX, DY);
6404 BlitBitmap(bitmap_db_door, drawto,
6405 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6406 DXSIZE, DYSIZE - p / 2, DX, DY);
6409 // printf("::: p == %d\n", p);
6410 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6414 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6417 int src1_x = g_right->src_x;
6418 int src1_y = g_right->src_y;
6419 int src2_x = g_left->src_x + g_left->width - i;
6420 int src2_y = g_left->src_y;
6421 int dst1_x = DX + DXSIZE - i;
6426 int height = DYSIZE;
6428 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6429 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6432 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6433 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6436 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6437 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6438 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6439 int dst2_x = DX, dst2_y = DY;
6440 int width = i, height = DYSIZE;
6442 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6443 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6446 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6447 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6451 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6454 int src1_x = g_right->src_x;
6455 int src1_y = g_right->src_y;
6456 int src2_x = g_left->src_x;
6457 int src2_y = g_left->src_y + g_left->height - i;
6459 int dst1_y = DY + DYSIZE - i;
6465 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6466 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6469 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6470 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6473 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6474 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6475 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6476 int dst2_x = DX, dst2_y = DY;
6477 int width = DXSIZE, height = i;
6479 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6480 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6483 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6484 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6488 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6490 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6493 int src1_x = g_right->src_x;
6494 int src1_y = g_right->src_y;
6495 int src2_x = g_left->src_x + g_left->width - i;
6496 int src2_y = g_left->src_y;
6497 int dst1_x = DX + DXSIZE - i;
6502 int height1 = 63, height2 = DYSIZE / 2 - height1;
6503 int ypos1 = 0, ypos2 = height2;
6504 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6506 SetClipOrigin(bm_right, gc_right,
6507 dst1_x - src1_x, dst1_y - src1_y + j);
6508 BlitBitmapMasked(bm_right, drawto,
6509 src1_x, src1_y + ypos1, width, height2,
6510 dst1_x, dst1_y + ypos1 + j);
6511 BlitBitmapMasked(bm_right, drawto,
6512 src1_x, src1_y + ypos3, width, height1,
6513 dst1_x, dst1_y + ypos3 + j);
6514 SetClipOrigin(bm_left, gc_left,
6515 dst2_x - src2_x, dst2_y - src2_y - j);
6516 BlitBitmapMasked(bm_left, drawto,
6517 src2_x, src2_y + ypos1 + j, width, height2 - j,
6518 dst2_x, dst2_y + ypos1);
6519 BlitBitmapMasked(bm_left, drawto,
6520 src2_x, src2_y + ypos3, width, height1,
6521 dst2_x, dst2_y + ypos3 - j);
6523 SetClipOrigin(bm_left, gc_left,
6524 dst2_x - src2_x, dst2_y - src2_y - j);
6525 BlitBitmapMasked(bm_left, drawto,
6526 src2_x, src2_y + ypos2, width, height1,
6527 dst2_x, dst2_y + ypos2 - j);
6528 BlitBitmapMasked(bm_left, drawto,
6529 src2_x, src2_y + ypos4, width, height2,
6530 dst2_x, dst2_y + ypos4 - j);
6531 SetClipOrigin(bm_right, gc_right,
6532 dst1_x - src1_x, dst1_y - src1_y + j);
6533 BlitBitmapMasked(bm_right, drawto,
6534 src1_x, src1_y + ypos2, width, height1,
6535 dst1_x, dst1_y + ypos2 + j);
6536 BlitBitmapMasked(bm_right, drawto,
6537 src1_x, src1_y + ypos4, width, height2 - j,
6538 dst1_x, dst1_y + ypos4 + j);
6541 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6542 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6543 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6544 int dst2_x = DX, dst2_y = DY;
6545 int width = i, height = DYSIZE;
6546 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6548 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6549 BlitBitmapMasked(bitmap, drawto,
6550 src1_x, src1_y, width, ypos2,
6551 dst1_x, dst1_y + j);
6552 BlitBitmapMasked(bitmap, drawto,
6553 src1_x, src1_y + ypos3, width, ypos1,
6554 dst1_x, dst1_y + ypos3 + j);
6555 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6556 BlitBitmapMasked(bitmap, drawto,
6557 src2_x, src2_y + j, width, ypos2 - j,
6559 BlitBitmapMasked(bitmap, drawto,
6560 src2_x, src2_y + ypos3, width, ypos1,
6561 dst2_x, dst2_y + ypos3 - j);
6563 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6564 BlitBitmapMasked(bitmap, drawto,
6565 src2_x, src2_y + ypos2, width, ypos1,
6566 dst2_x, dst2_y + ypos2 - j);
6567 BlitBitmapMasked(bitmap, drawto,
6568 src2_x, src2_y + ypos4, width, ypos2,
6569 dst2_x, dst2_y + ypos4 - j);
6570 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6571 BlitBitmapMasked(bitmap, drawto,
6572 src1_x, src1_y + ypos2, width, ypos1,
6573 dst1_x, dst1_y + ypos2 + j);
6574 BlitBitmapMasked(bitmap, drawto,
6575 src1_x, src1_y + ypos4, width, ypos2 - j,
6576 dst1_x, dst1_y + ypos4 + j);
6579 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6580 BlitBitmapMasked(bitmap, drawto,
6581 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6582 DX + DXSIZE - i, DY + j);
6583 BlitBitmapMasked(bitmap, drawto,
6584 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6585 DX + DXSIZE - i, DY + 140 + j);
6586 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6587 DY - (DOOR_GFX_PAGEY1 + j));
6588 BlitBitmapMasked(bitmap, drawto,
6589 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6591 BlitBitmapMasked(bitmap, drawto,
6592 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6595 BlitBitmapMasked(bitmap, drawto,
6596 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6598 BlitBitmapMasked(bitmap, drawto,
6599 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6601 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6602 BlitBitmapMasked(bitmap, drawto,
6603 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6604 DX + DXSIZE - i, DY + 77 + j);
6605 BlitBitmapMasked(bitmap, drawto,
6606 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6607 DX + DXSIZE - i, DY + 203 + j);
6612 redraw_mask |= REDRAW_DOOR_1;
6613 door_1_done = (a == end);
6616 if (door_state & DOOR_ACTION_2 &&
6617 x * door_2.step_offset <= door_size_2)
6619 int a = MIN(x * door_2.step_offset, door_size);
6620 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6621 int i = p + door_skip;
6624 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6625 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6626 Bitmap *bm_left = g_left->bitmap;
6627 Bitmap *bm_right = g_right->bitmap;
6628 GC gc_left = bm_left->stored_clip_gc;
6629 GC gc_right = bm_right->stored_clip_gc;
6632 int classic_vxsize = 100;
6633 int classic_vysize = 100;
6634 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6635 VYSIZE == classic_vysize);
6637 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6639 BlitBitmap(bitmap_db_door, drawto,
6640 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6641 VXSIZE, VYSIZE, VX, VY);
6643 else if (x <= VYSIZE)
6645 BlitBitmap(bitmap_db_door, drawto,
6646 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6647 VXSIZE, VYSIZE - p / 2, VX, VY);
6649 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6652 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6655 int src1_x = g_right->src_x;
6656 int src1_y = g_right->src_y;
6657 int src2_x = g_left->src_x + g_left->width - i;
6658 int src2_y = g_left->src_y;
6659 int dst1_x = VX + VXSIZE - i;
6664 int height = VYSIZE;
6666 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6667 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6670 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6671 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6674 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6675 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6676 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6677 int dst2_x = VX, dst2_y = VY;
6678 int width = i, height = VYSIZE;
6680 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6681 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6684 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6685 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6689 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6692 int src1_x = g_right->src_x;
6693 int src1_y = g_right->src_y;
6694 int src2_x = g_left->src_x;
6695 int src2_y = g_left->src_y + g_left->height - i;
6697 int dst1_y = VY + VYSIZE - i;
6703 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6704 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6707 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6708 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6711 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6712 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6713 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6714 int dst2_x = VX, dst2_y = VY;
6715 int width = VXSIZE, height = i;
6717 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6718 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6721 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6722 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6726 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6728 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6731 int src1_x = g_right->src_x;
6732 int src1_y = g_right->src_y;
6733 int src2_x = g_left->src_x + g_left->width - i;
6734 int src2_y = g_left->src_y;
6735 int dst1_x = VX + VXSIZE - i;
6740 int height = VYSIZE / 2;
6741 int ypos1 = 0, ypos2 = VYSIZE / 2;
6743 SetClipOrigin(bm_right, gc_right,
6744 dst1_x - src1_x, dst1_y - src1_y + j);
6745 BlitBitmapMasked(bm_right, drawto,
6746 src1_x, src1_y + ypos1, width, height,
6747 dst1_x, dst1_y + ypos1 + j);
6748 SetClipOrigin(bm_left, gc_left,
6749 dst2_x - src2_x, dst2_y - src2_y - j);
6750 BlitBitmapMasked(bm_left, drawto,
6751 src2_x, src2_y + ypos1 + j, width, height - j,
6752 dst2_x, dst2_y + ypos1);
6754 SetClipOrigin(bm_left, gc_left,
6755 dst2_x - src2_x, dst2_y - src2_y - j);
6756 BlitBitmapMasked(bm_left, drawto,
6757 src2_x, src2_y + ypos2, width, height,
6758 dst2_x, dst2_y + ypos2 - j);
6759 SetClipOrigin(bm_right, gc_right,
6760 dst1_x - src1_x, dst1_y - src1_y + j);
6761 BlitBitmapMasked(bm_right, drawto,
6762 src1_x, src1_y + ypos2, width, height - j,
6763 dst1_x, dst1_y + ypos2 + j);
6765 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6766 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6767 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6768 int dst2_x = VX, dst2_y = VY;
6769 int width = i, height = VYSIZE;
6770 int ypos = VYSIZE / 2;
6772 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6773 BlitBitmapMasked(bitmap, drawto,
6774 src1_x, src1_y, width, ypos,
6775 dst1_x, dst1_y + j);
6776 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6777 BlitBitmapMasked(bitmap, drawto,
6778 src2_x, src2_y + j, width, ypos - j,
6781 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6782 BlitBitmapMasked(bitmap, drawto,
6783 src2_x, src2_y + ypos, width, ypos,
6784 dst2_x, dst2_y + ypos - j);
6785 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6786 BlitBitmapMasked(bitmap, drawto,
6787 src1_x, src1_y + ypos, width, ypos - j,
6788 dst1_x, dst1_y + ypos + j);
6791 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6792 BlitBitmapMasked(bitmap, drawto,
6793 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6794 VX + VXSIZE - i, VY + j);
6795 SetClipOrigin(bitmap, gc,
6796 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6797 BlitBitmapMasked(bitmap, drawto,
6798 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6801 BlitBitmapMasked(bitmap, drawto,
6802 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6803 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6804 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6805 BlitBitmapMasked(bitmap, drawto,
6806 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6808 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6813 redraw_mask |= REDRAW_DOOR_2;
6814 door_2_done = (a == VXSIZE);
6817 if (!(door_state & DOOR_NO_DELAY))
6821 if (game_status == GAME_MODE_MAIN)
6824 WaitUntilDelayReached(&door_delay, door_delay_value);
6829 if (door_state & DOOR_ACTION_1)
6830 door1 = door_state & DOOR_ACTION_1;
6831 if (door_state & DOOR_ACTION_2)
6832 door2 = door_state & DOOR_ACTION_2;
6834 return (door1 | door2);
6839 void DrawSpecialEditorDoor()
6842 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6843 int top_border_width = gfx1->width;
6844 int top_border_height = gfx1->height;
6845 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6846 int ex = EX - outer_border;
6847 int ey = EY - outer_border;
6848 int vy = VY - outer_border;
6849 int exsize = EXSIZE + 2 * outer_border;
6851 CloseDoor(DOOR_CLOSE_2);
6853 /* draw bigger level editor toolbox window */
6854 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6855 top_border_width, top_border_height, ex, ey - top_border_height);
6856 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6857 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6859 /* draw bigger level editor toolbox window */
6860 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6861 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6863 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6864 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6868 redraw_mask |= REDRAW_ALL;
6871 void UndrawSpecialEditorDoor()
6874 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6875 int top_border_width = gfx1->width;
6876 int top_border_height = gfx1->height;
6877 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6878 int ex = EX - outer_border;
6879 int ey = EY - outer_border;
6880 int ey_top = ey - top_border_height;
6881 int exsize = EXSIZE + 2 * outer_border;
6882 int eysize = EYSIZE + 2 * outer_border;
6884 /* draw normal tape recorder window */
6885 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6887 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6888 ex, ey_top, top_border_width, top_border_height,
6890 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6891 ex, ey, exsize, eysize, ex, ey);
6895 // if screen background is set to "[NONE]", clear editor toolbox window
6896 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6897 ClearRectangle(drawto, ex, ey, exsize, eysize);
6900 /* draw normal tape recorder window */
6901 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6902 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6906 redraw_mask |= REDRAW_ALL;
6910 /* ---------- new tool button stuff ---------------------------------------- */
6917 struct TextPosInfo *pos;
6920 } toolbutton_info[NUM_TOOL_BUTTONS] =
6923 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6924 TOOL_CTRL_ID_YES, "yes"
6927 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6928 TOOL_CTRL_ID_NO, "no"
6931 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6932 TOOL_CTRL_ID_CONFIRM, "confirm"
6935 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6936 TOOL_CTRL_ID_PLAYER_1, "player 1"
6939 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6940 TOOL_CTRL_ID_PLAYER_2, "player 2"
6943 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6944 TOOL_CTRL_ID_PLAYER_3, "player 3"
6947 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6948 TOOL_CTRL_ID_PLAYER_4, "player 4"
6952 void CreateToolButtons()
6956 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6958 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6959 struct TextPosInfo *pos = toolbutton_info[i].pos;
6960 struct GadgetInfo *gi;
6961 Bitmap *deco_bitmap = None;
6962 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6963 unsigned int event_mask = GD_EVENT_RELEASED;
6966 int gd_x = gfx->src_x;
6967 int gd_y = gfx->src_y;
6968 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6969 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6972 if (global.use_envelope_request)
6973 setRequestPosition(&dx, &dy, TRUE);
6975 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6977 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6979 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6980 pos->size, &deco_bitmap, &deco_x, &deco_y);
6981 deco_xpos = (gfx->width - pos->size) / 2;
6982 deco_ypos = (gfx->height - pos->size) / 2;
6985 gi = CreateGadget(GDI_CUSTOM_ID, id,
6986 GDI_INFO_TEXT, toolbutton_info[i].infotext,
6987 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6988 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6989 GDI_WIDTH, gfx->width,
6990 GDI_HEIGHT, gfx->height,
6991 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6992 GDI_STATE, GD_BUTTON_UNPRESSED,
6993 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6994 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6995 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6996 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6997 GDI_DECORATION_SIZE, pos->size, pos->size,
6998 GDI_DECORATION_SHIFTING, 1, 1,
6999 GDI_DIRECT_DRAW, FALSE,
7000 GDI_EVENT_MASK, event_mask,
7001 GDI_CALLBACK_ACTION, HandleToolButtons,
7005 Error(ERR_EXIT, "cannot create gadget");
7007 tool_gadget[id] = gi;
7013 /* graphic position values for tool buttons */
7014 #define TOOL_BUTTON_YES_XPOS 2
7015 #define TOOL_BUTTON_YES_YPOS 250
7016 #define TOOL_BUTTON_YES_GFX_YPOS 0
7017 #define TOOL_BUTTON_YES_XSIZE 46
7018 #define TOOL_BUTTON_YES_YSIZE 28
7019 #define TOOL_BUTTON_NO_XPOS 52
7020 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7021 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7022 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7023 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7024 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7025 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7026 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7027 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7028 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7029 #define TOOL_BUTTON_PLAYER_XSIZE 30
7030 #define TOOL_BUTTON_PLAYER_YSIZE 30
7031 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7032 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7033 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7034 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7035 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7036 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7037 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7038 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7039 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7040 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7041 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7042 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7043 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7044 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7045 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7046 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7047 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7048 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7049 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7050 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7059 } toolbutton_info[NUM_TOOL_BUTTONS] =
7062 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7063 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7064 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7069 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7070 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7071 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7076 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7077 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7078 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7079 TOOL_CTRL_ID_CONFIRM,
7083 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7084 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7085 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7086 TOOL_CTRL_ID_PLAYER_1,
7090 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7091 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7092 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7093 TOOL_CTRL_ID_PLAYER_2,
7097 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7098 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7099 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7100 TOOL_CTRL_ID_PLAYER_3,
7104 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7105 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7106 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7107 TOOL_CTRL_ID_PLAYER_4,
7112 void CreateToolButtons()
7116 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7118 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7119 Bitmap *deco_bitmap = None;
7120 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7121 struct GadgetInfo *gi;
7122 unsigned int event_mask;
7123 int gd_xoffset, gd_yoffset;
7124 int gd_x1, gd_x2, gd_y;
7127 event_mask = GD_EVENT_RELEASED;
7129 gd_xoffset = toolbutton_info[i].xpos;
7130 gd_yoffset = toolbutton_info[i].ypos;
7131 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7132 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7133 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7135 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7137 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7139 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7140 &deco_bitmap, &deco_x, &deco_y);
7141 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7142 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7145 gi = CreateGadget(GDI_CUSTOM_ID, id,
7146 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7147 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7148 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7149 GDI_WIDTH, toolbutton_info[i].width,
7150 GDI_HEIGHT, toolbutton_info[i].height,
7151 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7152 GDI_STATE, GD_BUTTON_UNPRESSED,
7153 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7154 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7155 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7156 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7157 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7158 GDI_DECORATION_SHIFTING, 1, 1,
7159 GDI_DIRECT_DRAW, FALSE,
7160 GDI_EVENT_MASK, event_mask,
7161 GDI_CALLBACK_ACTION, HandleToolButtons,
7165 Error(ERR_EXIT, "cannot create gadget");
7167 tool_gadget[id] = gi;
7173 void FreeToolButtons()
7177 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7178 FreeGadget(tool_gadget[i]);
7181 static void UnmapToolButtons()
7185 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7186 UnmapGadget(tool_gadget[i]);
7189 static void HandleToolButtons(struct GadgetInfo *gi)
7191 request_gadget_id = gi->custom_id;
7194 static struct Mapping_EM_to_RND_object
7197 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7198 boolean is_backside; /* backside of moving element */
7204 em_object_mapping_list[] =
7207 Xblank, TRUE, FALSE,
7211 Yacid_splash_eB, FALSE, FALSE,
7212 EL_ACID_SPLASH_RIGHT, -1, -1
7215 Yacid_splash_wB, FALSE, FALSE,
7216 EL_ACID_SPLASH_LEFT, -1, -1
7219 #ifdef EM_ENGINE_BAD_ROLL
7221 Xstone_force_e, FALSE, FALSE,
7222 EL_ROCK, -1, MV_BIT_RIGHT
7225 Xstone_force_w, FALSE, FALSE,
7226 EL_ROCK, -1, MV_BIT_LEFT
7229 Xnut_force_e, FALSE, FALSE,
7230 EL_NUT, -1, MV_BIT_RIGHT
7233 Xnut_force_w, FALSE, FALSE,
7234 EL_NUT, -1, MV_BIT_LEFT
7237 Xspring_force_e, FALSE, FALSE,
7238 EL_SPRING, -1, MV_BIT_RIGHT
7241 Xspring_force_w, FALSE, FALSE,
7242 EL_SPRING, -1, MV_BIT_LEFT
7245 Xemerald_force_e, FALSE, FALSE,
7246 EL_EMERALD, -1, MV_BIT_RIGHT
7249 Xemerald_force_w, FALSE, FALSE,
7250 EL_EMERALD, -1, MV_BIT_LEFT
7253 Xdiamond_force_e, FALSE, FALSE,
7254 EL_DIAMOND, -1, MV_BIT_RIGHT
7257 Xdiamond_force_w, FALSE, FALSE,
7258 EL_DIAMOND, -1, MV_BIT_LEFT
7261 Xbomb_force_e, FALSE, FALSE,
7262 EL_BOMB, -1, MV_BIT_RIGHT
7265 Xbomb_force_w, FALSE, FALSE,
7266 EL_BOMB, -1, MV_BIT_LEFT
7268 #endif /* EM_ENGINE_BAD_ROLL */
7271 Xstone, TRUE, FALSE,
7275 Xstone_pause, FALSE, FALSE,
7279 Xstone_fall, FALSE, FALSE,
7283 Ystone_s, FALSE, FALSE,
7284 EL_ROCK, ACTION_FALLING, -1
7287 Ystone_sB, FALSE, TRUE,
7288 EL_ROCK, ACTION_FALLING, -1
7291 Ystone_e, FALSE, FALSE,
7292 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7295 Ystone_eB, FALSE, TRUE,
7296 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7299 Ystone_w, FALSE, FALSE,
7300 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7303 Ystone_wB, FALSE, TRUE,
7304 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7311 Xnut_pause, FALSE, FALSE,
7315 Xnut_fall, FALSE, FALSE,
7319 Ynut_s, FALSE, FALSE,
7320 EL_NUT, ACTION_FALLING, -1
7323 Ynut_sB, FALSE, TRUE,
7324 EL_NUT, ACTION_FALLING, -1
7327 Ynut_e, FALSE, FALSE,
7328 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7331 Ynut_eB, FALSE, TRUE,
7332 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7335 Ynut_w, FALSE, FALSE,
7336 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7339 Ynut_wB, FALSE, TRUE,
7340 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7343 Xbug_n, TRUE, FALSE,
7347 Xbug_e, TRUE, FALSE,
7348 EL_BUG_RIGHT, -1, -1
7351 Xbug_s, TRUE, FALSE,
7355 Xbug_w, TRUE, FALSE,
7359 Xbug_gon, FALSE, FALSE,
7363 Xbug_goe, FALSE, FALSE,
7364 EL_BUG_RIGHT, -1, -1
7367 Xbug_gos, FALSE, FALSE,
7371 Xbug_gow, FALSE, FALSE,
7375 Ybug_n, FALSE, FALSE,
7376 EL_BUG, ACTION_MOVING, MV_BIT_UP
7379 Ybug_nB, FALSE, TRUE,
7380 EL_BUG, ACTION_MOVING, MV_BIT_UP
7383 Ybug_e, FALSE, FALSE,
7384 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7387 Ybug_eB, FALSE, TRUE,
7388 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7391 Ybug_s, FALSE, FALSE,
7392 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7395 Ybug_sB, FALSE, TRUE,
7396 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7399 Ybug_w, FALSE, FALSE,
7400 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7403 Ybug_wB, FALSE, TRUE,
7404 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7407 Ybug_w_n, FALSE, FALSE,
7408 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7411 Ybug_n_e, FALSE, FALSE,
7412 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7415 Ybug_e_s, FALSE, FALSE,
7416 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7419 Ybug_s_w, FALSE, FALSE,
7420 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7423 Ybug_e_n, FALSE, FALSE,
7424 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7427 Ybug_s_e, FALSE, FALSE,
7428 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7431 Ybug_w_s, FALSE, FALSE,
7432 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7435 Ybug_n_w, FALSE, FALSE,
7436 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7439 Ybug_stone, FALSE, FALSE,
7440 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7443 Ybug_spring, FALSE, FALSE,
7444 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7447 Xtank_n, TRUE, FALSE,
7448 EL_SPACESHIP_UP, -1, -1
7451 Xtank_e, TRUE, FALSE,
7452 EL_SPACESHIP_RIGHT, -1, -1
7455 Xtank_s, TRUE, FALSE,
7456 EL_SPACESHIP_DOWN, -1, -1
7459 Xtank_w, TRUE, FALSE,
7460 EL_SPACESHIP_LEFT, -1, -1
7463 Xtank_gon, FALSE, FALSE,
7464 EL_SPACESHIP_UP, -1, -1
7467 Xtank_goe, FALSE, FALSE,
7468 EL_SPACESHIP_RIGHT, -1, -1
7471 Xtank_gos, FALSE, FALSE,
7472 EL_SPACESHIP_DOWN, -1, -1
7475 Xtank_gow, FALSE, FALSE,
7476 EL_SPACESHIP_LEFT, -1, -1
7479 Ytank_n, FALSE, FALSE,
7480 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7483 Ytank_nB, FALSE, TRUE,
7484 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7487 Ytank_e, FALSE, FALSE,
7488 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7491 Ytank_eB, FALSE, TRUE,
7492 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7495 Ytank_s, FALSE, FALSE,
7496 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7499 Ytank_sB, FALSE, TRUE,
7500 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7503 Ytank_w, FALSE, FALSE,
7504 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7507 Ytank_wB, FALSE, TRUE,
7508 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7511 Ytank_w_n, FALSE, FALSE,
7512 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7515 Ytank_n_e, FALSE, FALSE,
7516 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7519 Ytank_e_s, FALSE, FALSE,
7520 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7523 Ytank_s_w, FALSE, FALSE,
7524 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7527 Ytank_e_n, FALSE, FALSE,
7528 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7531 Ytank_s_e, FALSE, FALSE,
7532 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7535 Ytank_w_s, FALSE, FALSE,
7536 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7539 Ytank_n_w, FALSE, FALSE,
7540 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7543 Ytank_stone, FALSE, FALSE,
7544 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7547 Ytank_spring, FALSE, FALSE,
7548 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7551 Xandroid, TRUE, FALSE,
7552 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7555 Xandroid_1_n, FALSE, FALSE,
7556 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7559 Xandroid_2_n, FALSE, FALSE,
7560 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7563 Xandroid_1_e, FALSE, FALSE,
7564 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7567 Xandroid_2_e, FALSE, FALSE,
7568 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7571 Xandroid_1_w, FALSE, FALSE,
7572 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7575 Xandroid_2_w, FALSE, FALSE,
7576 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7579 Xandroid_1_s, FALSE, FALSE,
7580 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7583 Xandroid_2_s, FALSE, FALSE,
7584 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7587 Yandroid_n, FALSE, FALSE,
7588 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7591 Yandroid_nB, FALSE, TRUE,
7592 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7595 Yandroid_ne, FALSE, FALSE,
7596 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7599 Yandroid_neB, FALSE, TRUE,
7600 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7603 Yandroid_e, FALSE, FALSE,
7604 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7607 Yandroid_eB, FALSE, TRUE,
7608 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7611 Yandroid_se, FALSE, FALSE,
7612 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7615 Yandroid_seB, FALSE, TRUE,
7616 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7619 Yandroid_s, FALSE, FALSE,
7620 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7623 Yandroid_sB, FALSE, TRUE,
7624 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7627 Yandroid_sw, FALSE, FALSE,
7628 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7631 Yandroid_swB, FALSE, TRUE,
7632 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7635 Yandroid_w, FALSE, FALSE,
7636 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7639 Yandroid_wB, FALSE, TRUE,
7640 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7643 Yandroid_nw, FALSE, FALSE,
7644 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7647 Yandroid_nwB, FALSE, TRUE,
7648 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7651 Xspring, TRUE, FALSE,
7655 Xspring_pause, FALSE, FALSE,
7659 Xspring_e, FALSE, FALSE,
7663 Xspring_w, FALSE, FALSE,
7667 Xspring_fall, FALSE, FALSE,
7671 Yspring_s, FALSE, FALSE,
7672 EL_SPRING, ACTION_FALLING, -1
7675 Yspring_sB, FALSE, TRUE,
7676 EL_SPRING, ACTION_FALLING, -1
7679 Yspring_e, FALSE, FALSE,
7680 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7683 Yspring_eB, FALSE, TRUE,
7684 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7687 Yspring_w, FALSE, FALSE,
7688 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7691 Yspring_wB, FALSE, TRUE,
7692 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7695 Yspring_kill_e, FALSE, FALSE,
7696 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7699 Yspring_kill_eB, FALSE, TRUE,
7700 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7703 Yspring_kill_w, FALSE, FALSE,
7704 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7707 Yspring_kill_wB, FALSE, TRUE,
7708 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7711 Xeater_n, TRUE, FALSE,
7712 EL_YAMYAM_UP, -1, -1
7715 Xeater_e, TRUE, FALSE,
7716 EL_YAMYAM_RIGHT, -1, -1
7719 Xeater_w, TRUE, FALSE,
7720 EL_YAMYAM_LEFT, -1, -1
7723 Xeater_s, TRUE, FALSE,
7724 EL_YAMYAM_DOWN, -1, -1
7727 Yeater_n, FALSE, FALSE,
7728 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7731 Yeater_nB, FALSE, TRUE,
7732 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7735 Yeater_e, FALSE, FALSE,
7736 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7739 Yeater_eB, FALSE, TRUE,
7740 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7743 Yeater_s, FALSE, FALSE,
7744 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7747 Yeater_sB, FALSE, TRUE,
7748 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7751 Yeater_w, FALSE, FALSE,
7752 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7755 Yeater_wB, FALSE, TRUE,
7756 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7759 Yeater_stone, FALSE, FALSE,
7760 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7763 Yeater_spring, FALSE, FALSE,
7764 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7767 Xalien, TRUE, FALSE,
7771 Xalien_pause, FALSE, FALSE,
7775 Yalien_n, FALSE, FALSE,
7776 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7779 Yalien_nB, FALSE, TRUE,
7780 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7783 Yalien_e, FALSE, FALSE,
7784 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7787 Yalien_eB, FALSE, TRUE,
7788 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7791 Yalien_s, FALSE, FALSE,
7792 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7795 Yalien_sB, FALSE, TRUE,
7796 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7799 Yalien_w, FALSE, FALSE,
7800 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7803 Yalien_wB, FALSE, TRUE,
7804 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7807 Yalien_stone, FALSE, FALSE,
7808 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7811 Yalien_spring, FALSE, FALSE,
7812 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7815 Xemerald, TRUE, FALSE,
7819 Xemerald_pause, FALSE, FALSE,
7823 Xemerald_fall, FALSE, FALSE,
7827 Xemerald_shine, FALSE, FALSE,
7828 EL_EMERALD, ACTION_TWINKLING, -1
7831 Yemerald_s, FALSE, FALSE,
7832 EL_EMERALD, ACTION_FALLING, -1
7835 Yemerald_sB, FALSE, TRUE,
7836 EL_EMERALD, ACTION_FALLING, -1
7839 Yemerald_e, FALSE, FALSE,
7840 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7843 Yemerald_eB, FALSE, TRUE,
7844 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7847 Yemerald_w, FALSE, FALSE,
7848 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7851 Yemerald_wB, FALSE, TRUE,
7852 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7855 Yemerald_eat, FALSE, FALSE,
7856 EL_EMERALD, ACTION_COLLECTING, -1
7859 Yemerald_stone, FALSE, FALSE,
7860 EL_NUT, ACTION_BREAKING, -1
7863 Xdiamond, TRUE, FALSE,
7867 Xdiamond_pause, FALSE, FALSE,
7871 Xdiamond_fall, FALSE, FALSE,
7875 Xdiamond_shine, FALSE, FALSE,
7876 EL_DIAMOND, ACTION_TWINKLING, -1
7879 Ydiamond_s, FALSE, FALSE,
7880 EL_DIAMOND, ACTION_FALLING, -1
7883 Ydiamond_sB, FALSE, TRUE,
7884 EL_DIAMOND, ACTION_FALLING, -1
7887 Ydiamond_e, FALSE, FALSE,
7888 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7891 Ydiamond_eB, FALSE, TRUE,
7892 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7895 Ydiamond_w, FALSE, FALSE,
7896 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7899 Ydiamond_wB, FALSE, TRUE,
7900 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7903 Ydiamond_eat, FALSE, FALSE,
7904 EL_DIAMOND, ACTION_COLLECTING, -1
7907 Ydiamond_stone, FALSE, FALSE,
7908 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7911 Xdrip_fall, TRUE, FALSE,
7912 EL_AMOEBA_DROP, -1, -1
7915 Xdrip_stretch, FALSE, FALSE,
7916 EL_AMOEBA_DROP, ACTION_FALLING, -1
7919 Xdrip_stretchB, FALSE, TRUE,
7920 EL_AMOEBA_DROP, ACTION_FALLING, -1
7923 Xdrip_eat, FALSE, FALSE,
7924 EL_AMOEBA_DROP, ACTION_GROWING, -1
7927 Ydrip_s1, FALSE, FALSE,
7928 EL_AMOEBA_DROP, ACTION_FALLING, -1
7931 Ydrip_s1B, FALSE, TRUE,
7932 EL_AMOEBA_DROP, ACTION_FALLING, -1
7935 Ydrip_s2, FALSE, FALSE,
7936 EL_AMOEBA_DROP, ACTION_FALLING, -1
7939 Ydrip_s2B, FALSE, TRUE,
7940 EL_AMOEBA_DROP, ACTION_FALLING, -1
7947 Xbomb_pause, FALSE, FALSE,
7951 Xbomb_fall, FALSE, FALSE,
7955 Ybomb_s, FALSE, FALSE,
7956 EL_BOMB, ACTION_FALLING, -1
7959 Ybomb_sB, FALSE, TRUE,
7960 EL_BOMB, ACTION_FALLING, -1
7963 Ybomb_e, FALSE, FALSE,
7964 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7967 Ybomb_eB, FALSE, TRUE,
7968 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7971 Ybomb_w, FALSE, FALSE,
7972 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7975 Ybomb_wB, FALSE, TRUE,
7976 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
7979 Ybomb_eat, FALSE, FALSE,
7980 EL_BOMB, ACTION_ACTIVATING, -1
7983 Xballoon, TRUE, FALSE,
7987 Yballoon_n, FALSE, FALSE,
7988 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7991 Yballoon_nB, FALSE, TRUE,
7992 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
7995 Yballoon_e, FALSE, FALSE,
7996 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
7999 Yballoon_eB, FALSE, TRUE,
8000 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8003 Yballoon_s, FALSE, FALSE,
8004 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8007 Yballoon_sB, FALSE, TRUE,
8008 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8011 Yballoon_w, FALSE, FALSE,
8012 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8015 Yballoon_wB, FALSE, TRUE,
8016 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8019 Xgrass, TRUE, FALSE,
8020 EL_EMC_GRASS, -1, -1
8023 Ygrass_nB, FALSE, FALSE,
8024 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8027 Ygrass_eB, FALSE, FALSE,
8028 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8031 Ygrass_sB, FALSE, FALSE,
8032 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8035 Ygrass_wB, FALSE, FALSE,
8036 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8043 Ydirt_nB, FALSE, FALSE,
8044 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8047 Ydirt_eB, FALSE, FALSE,
8048 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8051 Ydirt_sB, FALSE, FALSE,
8052 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8055 Ydirt_wB, FALSE, FALSE,
8056 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8059 Xacid_ne, TRUE, FALSE,
8060 EL_ACID_POOL_TOPRIGHT, -1, -1
8063 Xacid_se, TRUE, FALSE,
8064 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8067 Xacid_s, TRUE, FALSE,
8068 EL_ACID_POOL_BOTTOM, -1, -1
8071 Xacid_sw, TRUE, FALSE,
8072 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8075 Xacid_nw, TRUE, FALSE,
8076 EL_ACID_POOL_TOPLEFT, -1, -1
8079 Xacid_1, TRUE, FALSE,
8083 Xacid_2, FALSE, FALSE,
8087 Xacid_3, FALSE, FALSE,
8091 Xacid_4, FALSE, FALSE,
8095 Xacid_5, FALSE, FALSE,
8099 Xacid_6, FALSE, FALSE,
8103 Xacid_7, FALSE, FALSE,
8107 Xacid_8, FALSE, FALSE,
8111 Xball_1, TRUE, FALSE,
8112 EL_EMC_MAGIC_BALL, -1, -1
8115 Xball_1B, FALSE, FALSE,
8116 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8119 Xball_2, FALSE, FALSE,
8120 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8123 Xball_2B, FALSE, FALSE,
8124 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8127 Yball_eat, FALSE, FALSE,
8128 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8131 Ykey_1_eat, FALSE, FALSE,
8132 EL_EM_KEY_1, ACTION_COLLECTING, -1
8135 Ykey_2_eat, FALSE, FALSE,
8136 EL_EM_KEY_2, ACTION_COLLECTING, -1
8139 Ykey_3_eat, FALSE, FALSE,
8140 EL_EM_KEY_3, ACTION_COLLECTING, -1
8143 Ykey_4_eat, FALSE, FALSE,
8144 EL_EM_KEY_4, ACTION_COLLECTING, -1
8147 Ykey_5_eat, FALSE, FALSE,
8148 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8151 Ykey_6_eat, FALSE, FALSE,
8152 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8155 Ykey_7_eat, FALSE, FALSE,
8156 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8159 Ykey_8_eat, FALSE, FALSE,
8160 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8163 Ylenses_eat, FALSE, FALSE,
8164 EL_EMC_LENSES, ACTION_COLLECTING, -1
8167 Ymagnify_eat, FALSE, FALSE,
8168 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8171 Ygrass_eat, FALSE, FALSE,
8172 EL_EMC_GRASS, ACTION_SNAPPING, -1
8175 Ydirt_eat, FALSE, FALSE,
8176 EL_SAND, ACTION_SNAPPING, -1
8179 Xgrow_ns, TRUE, FALSE,
8180 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8183 Ygrow_ns_eat, FALSE, FALSE,
8184 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8187 Xgrow_ew, TRUE, FALSE,
8188 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8191 Ygrow_ew_eat, FALSE, FALSE,
8192 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8195 Xwonderwall, TRUE, FALSE,
8196 EL_MAGIC_WALL, -1, -1
8199 XwonderwallB, FALSE, FALSE,
8200 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8203 Xamoeba_1, TRUE, FALSE,
8204 EL_AMOEBA_DRY, ACTION_OTHER, -1
8207 Xamoeba_2, FALSE, FALSE,
8208 EL_AMOEBA_DRY, ACTION_OTHER, -1
8211 Xamoeba_3, FALSE, FALSE,
8212 EL_AMOEBA_DRY, ACTION_OTHER, -1
8215 Xamoeba_4, FALSE, FALSE,
8216 EL_AMOEBA_DRY, ACTION_OTHER, -1
8219 Xamoeba_5, TRUE, FALSE,
8220 EL_AMOEBA_WET, ACTION_OTHER, -1
8223 Xamoeba_6, FALSE, FALSE,
8224 EL_AMOEBA_WET, ACTION_OTHER, -1
8227 Xamoeba_7, FALSE, FALSE,
8228 EL_AMOEBA_WET, ACTION_OTHER, -1
8231 Xamoeba_8, FALSE, FALSE,
8232 EL_AMOEBA_WET, ACTION_OTHER, -1
8235 Xdoor_1, TRUE, FALSE,
8236 EL_EM_GATE_1, -1, -1
8239 Xdoor_2, TRUE, FALSE,
8240 EL_EM_GATE_2, -1, -1
8243 Xdoor_3, TRUE, FALSE,
8244 EL_EM_GATE_3, -1, -1
8247 Xdoor_4, TRUE, FALSE,
8248 EL_EM_GATE_4, -1, -1
8251 Xdoor_5, TRUE, FALSE,
8252 EL_EMC_GATE_5, -1, -1
8255 Xdoor_6, TRUE, FALSE,
8256 EL_EMC_GATE_6, -1, -1
8259 Xdoor_7, TRUE, FALSE,
8260 EL_EMC_GATE_7, -1, -1
8263 Xdoor_8, TRUE, FALSE,
8264 EL_EMC_GATE_8, -1, -1
8267 Xkey_1, TRUE, FALSE,
8271 Xkey_2, TRUE, FALSE,
8275 Xkey_3, TRUE, FALSE,
8279 Xkey_4, TRUE, FALSE,
8283 Xkey_5, TRUE, FALSE,
8284 EL_EMC_KEY_5, -1, -1
8287 Xkey_6, TRUE, FALSE,
8288 EL_EMC_KEY_6, -1, -1
8291 Xkey_7, TRUE, FALSE,
8292 EL_EMC_KEY_7, -1, -1
8295 Xkey_8, TRUE, FALSE,
8296 EL_EMC_KEY_8, -1, -1
8299 Xwind_n, TRUE, FALSE,
8300 EL_BALLOON_SWITCH_UP, -1, -1
8303 Xwind_e, TRUE, FALSE,
8304 EL_BALLOON_SWITCH_RIGHT, -1, -1
8307 Xwind_s, TRUE, FALSE,
8308 EL_BALLOON_SWITCH_DOWN, -1, -1
8311 Xwind_w, TRUE, FALSE,
8312 EL_BALLOON_SWITCH_LEFT, -1, -1
8315 Xwind_nesw, TRUE, FALSE,
8316 EL_BALLOON_SWITCH_ANY, -1, -1
8319 Xwind_stop, TRUE, FALSE,
8320 EL_BALLOON_SWITCH_NONE, -1, -1
8324 EL_EM_EXIT_CLOSED, -1, -1
8327 Xexit_1, TRUE, FALSE,
8328 EL_EM_EXIT_OPEN, -1, -1
8331 Xexit_2, FALSE, FALSE,
8332 EL_EM_EXIT_OPEN, -1, -1
8335 Xexit_3, FALSE, FALSE,
8336 EL_EM_EXIT_OPEN, -1, -1
8339 Xdynamite, TRUE, FALSE,
8340 EL_EM_DYNAMITE, -1, -1
8343 Ydynamite_eat, FALSE, FALSE,
8344 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8347 Xdynamite_1, TRUE, FALSE,
8348 EL_EM_DYNAMITE_ACTIVE, -1, -1
8351 Xdynamite_2, FALSE, FALSE,
8352 EL_EM_DYNAMITE_ACTIVE, -1, -1
8355 Xdynamite_3, FALSE, FALSE,
8356 EL_EM_DYNAMITE_ACTIVE, -1, -1
8359 Xdynamite_4, FALSE, FALSE,
8360 EL_EM_DYNAMITE_ACTIVE, -1, -1
8363 Xbumper, TRUE, FALSE,
8364 EL_EMC_SPRING_BUMPER, -1, -1
8367 XbumperB, FALSE, FALSE,
8368 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8371 Xwheel, TRUE, FALSE,
8372 EL_ROBOT_WHEEL, -1, -1
8375 XwheelB, FALSE, FALSE,
8376 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8379 Xswitch, TRUE, FALSE,
8380 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8383 XswitchB, FALSE, FALSE,
8384 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8388 EL_QUICKSAND_EMPTY, -1, -1
8391 Xsand_stone, TRUE, FALSE,
8392 EL_QUICKSAND_FULL, -1, -1
8395 Xsand_stonein_1, FALSE, TRUE,
8396 EL_ROCK, ACTION_FILLING, -1
8399 Xsand_stonein_2, FALSE, TRUE,
8400 EL_ROCK, ACTION_FILLING, -1
8403 Xsand_stonein_3, FALSE, TRUE,
8404 EL_ROCK, ACTION_FILLING, -1
8407 Xsand_stonein_4, FALSE, TRUE,
8408 EL_ROCK, ACTION_FILLING, -1
8412 Xsand_stonesand_1, FALSE, FALSE,
8413 EL_QUICKSAND_EMPTYING, -1, -1
8416 Xsand_stonesand_2, FALSE, FALSE,
8417 EL_QUICKSAND_EMPTYING, -1, -1
8420 Xsand_stonesand_3, FALSE, FALSE,
8421 EL_QUICKSAND_EMPTYING, -1, -1
8424 Xsand_stonesand_4, FALSE, FALSE,
8425 EL_QUICKSAND_EMPTYING, -1, -1
8428 Xsand_stonesand_quickout_1, FALSE, FALSE,
8429 EL_QUICKSAND_EMPTYING, -1, -1
8432 Xsand_stonesand_quickout_2, FALSE, FALSE,
8433 EL_QUICKSAND_EMPTYING, -1, -1
8437 Xsand_stonesand_1, FALSE, FALSE,
8438 EL_QUICKSAND_FULL, -1, -1
8441 Xsand_stonesand_2, FALSE, FALSE,
8442 EL_QUICKSAND_FULL, -1, -1
8445 Xsand_stonesand_3, FALSE, FALSE,
8446 EL_QUICKSAND_FULL, -1, -1
8449 Xsand_stonesand_4, FALSE, FALSE,
8450 EL_QUICKSAND_FULL, -1, -1
8454 Xsand_stoneout_1, FALSE, FALSE,
8455 EL_ROCK, ACTION_EMPTYING, -1
8458 Xsand_stoneout_2, FALSE, FALSE,
8459 EL_ROCK, ACTION_EMPTYING, -1
8463 Xsand_sandstone_1, FALSE, FALSE,
8464 EL_QUICKSAND_FILLING, -1, -1
8467 Xsand_sandstone_2, FALSE, FALSE,
8468 EL_QUICKSAND_FILLING, -1, -1
8471 Xsand_sandstone_3, FALSE, FALSE,
8472 EL_QUICKSAND_FILLING, -1, -1
8475 Xsand_sandstone_4, FALSE, FALSE,
8476 EL_QUICKSAND_FILLING, -1, -1
8480 Xsand_sandstone_1, FALSE, FALSE,
8481 EL_QUICKSAND_FULL, -1, -1
8484 Xsand_sandstone_2, FALSE, FALSE,
8485 EL_QUICKSAND_FULL, -1, -1
8488 Xsand_sandstone_3, FALSE, FALSE,
8489 EL_QUICKSAND_FULL, -1, -1
8492 Xsand_sandstone_4, FALSE, FALSE,
8493 EL_QUICKSAND_FULL, -1, -1
8497 Xplant, TRUE, FALSE,
8498 EL_EMC_PLANT, -1, -1
8501 Yplant, FALSE, FALSE,
8502 EL_EMC_PLANT, -1, -1
8505 Xlenses, TRUE, FALSE,
8506 EL_EMC_LENSES, -1, -1
8509 Xmagnify, TRUE, FALSE,
8510 EL_EMC_MAGNIFIER, -1, -1
8513 Xdripper, TRUE, FALSE,
8514 EL_EMC_DRIPPER, -1, -1
8517 XdripperB, FALSE, FALSE,
8518 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8521 Xfake_blank, TRUE, FALSE,
8522 EL_INVISIBLE_WALL, -1, -1
8525 Xfake_blankB, FALSE, FALSE,
8526 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8529 Xfake_grass, TRUE, FALSE,
8530 EL_EMC_FAKE_GRASS, -1, -1
8533 Xfake_grassB, FALSE, FALSE,
8534 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8537 Xfake_door_1, TRUE, FALSE,
8538 EL_EM_GATE_1_GRAY, -1, -1
8541 Xfake_door_2, TRUE, FALSE,
8542 EL_EM_GATE_2_GRAY, -1, -1
8545 Xfake_door_3, TRUE, FALSE,
8546 EL_EM_GATE_3_GRAY, -1, -1
8549 Xfake_door_4, TRUE, FALSE,
8550 EL_EM_GATE_4_GRAY, -1, -1
8553 Xfake_door_5, TRUE, FALSE,
8554 EL_EMC_GATE_5_GRAY, -1, -1
8557 Xfake_door_6, TRUE, FALSE,
8558 EL_EMC_GATE_6_GRAY, -1, -1
8561 Xfake_door_7, TRUE, FALSE,
8562 EL_EMC_GATE_7_GRAY, -1, -1
8565 Xfake_door_8, TRUE, FALSE,
8566 EL_EMC_GATE_8_GRAY, -1, -1
8569 Xfake_acid_1, TRUE, FALSE,
8570 EL_EMC_FAKE_ACID, -1, -1
8573 Xfake_acid_2, FALSE, FALSE,
8574 EL_EMC_FAKE_ACID, -1, -1
8577 Xfake_acid_3, FALSE, FALSE,
8578 EL_EMC_FAKE_ACID, -1, -1
8581 Xfake_acid_4, FALSE, FALSE,
8582 EL_EMC_FAKE_ACID, -1, -1
8585 Xfake_acid_5, FALSE, FALSE,
8586 EL_EMC_FAKE_ACID, -1, -1
8589 Xfake_acid_6, FALSE, FALSE,
8590 EL_EMC_FAKE_ACID, -1, -1
8593 Xfake_acid_7, FALSE, FALSE,
8594 EL_EMC_FAKE_ACID, -1, -1
8597 Xfake_acid_8, FALSE, FALSE,
8598 EL_EMC_FAKE_ACID, -1, -1
8601 Xsteel_1, TRUE, FALSE,
8602 EL_STEELWALL, -1, -1
8605 Xsteel_2, TRUE, FALSE,
8606 EL_EMC_STEELWALL_2, -1, -1
8609 Xsteel_3, TRUE, FALSE,
8610 EL_EMC_STEELWALL_3, -1, -1
8613 Xsteel_4, TRUE, FALSE,
8614 EL_EMC_STEELWALL_4, -1, -1
8617 Xwall_1, TRUE, FALSE,
8621 Xwall_2, TRUE, FALSE,
8622 EL_EMC_WALL_14, -1, -1
8625 Xwall_3, TRUE, FALSE,
8626 EL_EMC_WALL_15, -1, -1
8629 Xwall_4, TRUE, FALSE,
8630 EL_EMC_WALL_16, -1, -1
8633 Xround_wall_1, TRUE, FALSE,
8634 EL_WALL_SLIPPERY, -1, -1
8637 Xround_wall_2, TRUE, FALSE,
8638 EL_EMC_WALL_SLIPPERY_2, -1, -1
8641 Xround_wall_3, TRUE, FALSE,
8642 EL_EMC_WALL_SLIPPERY_3, -1, -1
8645 Xround_wall_4, TRUE, FALSE,
8646 EL_EMC_WALL_SLIPPERY_4, -1, -1
8649 Xdecor_1, TRUE, FALSE,
8650 EL_EMC_WALL_8, -1, -1
8653 Xdecor_2, TRUE, FALSE,
8654 EL_EMC_WALL_6, -1, -1
8657 Xdecor_3, TRUE, FALSE,
8658 EL_EMC_WALL_4, -1, -1
8661 Xdecor_4, TRUE, FALSE,
8662 EL_EMC_WALL_7, -1, -1
8665 Xdecor_5, TRUE, FALSE,
8666 EL_EMC_WALL_5, -1, -1
8669 Xdecor_6, TRUE, FALSE,
8670 EL_EMC_WALL_9, -1, -1
8673 Xdecor_7, TRUE, FALSE,
8674 EL_EMC_WALL_10, -1, -1
8677 Xdecor_8, TRUE, FALSE,
8678 EL_EMC_WALL_1, -1, -1
8681 Xdecor_9, TRUE, FALSE,
8682 EL_EMC_WALL_2, -1, -1
8685 Xdecor_10, TRUE, FALSE,
8686 EL_EMC_WALL_3, -1, -1
8689 Xdecor_11, TRUE, FALSE,
8690 EL_EMC_WALL_11, -1, -1
8693 Xdecor_12, TRUE, FALSE,
8694 EL_EMC_WALL_12, -1, -1
8697 Xalpha_0, TRUE, FALSE,
8698 EL_CHAR('0'), -1, -1
8701 Xalpha_1, TRUE, FALSE,
8702 EL_CHAR('1'), -1, -1
8705 Xalpha_2, TRUE, FALSE,
8706 EL_CHAR('2'), -1, -1
8709 Xalpha_3, TRUE, FALSE,
8710 EL_CHAR('3'), -1, -1
8713 Xalpha_4, TRUE, FALSE,
8714 EL_CHAR('4'), -1, -1
8717 Xalpha_5, TRUE, FALSE,
8718 EL_CHAR('5'), -1, -1
8721 Xalpha_6, TRUE, FALSE,
8722 EL_CHAR('6'), -1, -1
8725 Xalpha_7, TRUE, FALSE,
8726 EL_CHAR('7'), -1, -1
8729 Xalpha_8, TRUE, FALSE,
8730 EL_CHAR('8'), -1, -1
8733 Xalpha_9, TRUE, FALSE,
8734 EL_CHAR('9'), -1, -1
8737 Xalpha_excla, TRUE, FALSE,
8738 EL_CHAR('!'), -1, -1
8741 Xalpha_quote, TRUE, FALSE,
8742 EL_CHAR('"'), -1, -1
8745 Xalpha_comma, TRUE, FALSE,
8746 EL_CHAR(','), -1, -1
8749 Xalpha_minus, TRUE, FALSE,
8750 EL_CHAR('-'), -1, -1
8753 Xalpha_perio, TRUE, FALSE,
8754 EL_CHAR('.'), -1, -1
8757 Xalpha_colon, TRUE, FALSE,
8758 EL_CHAR(':'), -1, -1
8761 Xalpha_quest, TRUE, FALSE,
8762 EL_CHAR('?'), -1, -1
8765 Xalpha_a, TRUE, FALSE,
8766 EL_CHAR('A'), -1, -1
8769 Xalpha_b, TRUE, FALSE,
8770 EL_CHAR('B'), -1, -1
8773 Xalpha_c, TRUE, FALSE,
8774 EL_CHAR('C'), -1, -1
8777 Xalpha_d, TRUE, FALSE,
8778 EL_CHAR('D'), -1, -1
8781 Xalpha_e, TRUE, FALSE,
8782 EL_CHAR('E'), -1, -1
8785 Xalpha_f, TRUE, FALSE,
8786 EL_CHAR('F'), -1, -1
8789 Xalpha_g, TRUE, FALSE,
8790 EL_CHAR('G'), -1, -1
8793 Xalpha_h, TRUE, FALSE,
8794 EL_CHAR('H'), -1, -1
8797 Xalpha_i, TRUE, FALSE,
8798 EL_CHAR('I'), -1, -1
8801 Xalpha_j, TRUE, FALSE,
8802 EL_CHAR('J'), -1, -1
8805 Xalpha_k, TRUE, FALSE,
8806 EL_CHAR('K'), -1, -1
8809 Xalpha_l, TRUE, FALSE,
8810 EL_CHAR('L'), -1, -1
8813 Xalpha_m, TRUE, FALSE,
8814 EL_CHAR('M'), -1, -1
8817 Xalpha_n, TRUE, FALSE,
8818 EL_CHAR('N'), -1, -1
8821 Xalpha_o, TRUE, FALSE,
8822 EL_CHAR('O'), -1, -1
8825 Xalpha_p, TRUE, FALSE,
8826 EL_CHAR('P'), -1, -1
8829 Xalpha_q, TRUE, FALSE,
8830 EL_CHAR('Q'), -1, -1
8833 Xalpha_r, TRUE, FALSE,
8834 EL_CHAR('R'), -1, -1
8837 Xalpha_s, TRUE, FALSE,
8838 EL_CHAR('S'), -1, -1
8841 Xalpha_t, TRUE, FALSE,
8842 EL_CHAR('T'), -1, -1
8845 Xalpha_u, TRUE, FALSE,
8846 EL_CHAR('U'), -1, -1
8849 Xalpha_v, TRUE, FALSE,
8850 EL_CHAR('V'), -1, -1
8853 Xalpha_w, TRUE, FALSE,
8854 EL_CHAR('W'), -1, -1
8857 Xalpha_x, TRUE, FALSE,
8858 EL_CHAR('X'), -1, -1
8861 Xalpha_y, TRUE, FALSE,
8862 EL_CHAR('Y'), -1, -1
8865 Xalpha_z, TRUE, FALSE,
8866 EL_CHAR('Z'), -1, -1
8869 Xalpha_arrow_e, TRUE, FALSE,
8870 EL_CHAR('>'), -1, -1
8873 Xalpha_arrow_w, TRUE, FALSE,
8874 EL_CHAR('<'), -1, -1
8877 Xalpha_copyr, TRUE, FALSE,
8878 EL_CHAR('©'), -1, -1
8882 Xboom_bug, FALSE, FALSE,
8883 EL_BUG, ACTION_EXPLODING, -1
8886 Xboom_bomb, FALSE, FALSE,
8887 EL_BOMB, ACTION_EXPLODING, -1
8890 Xboom_android, FALSE, FALSE,
8891 EL_EMC_ANDROID, ACTION_OTHER, -1
8894 Xboom_1, FALSE, FALSE,
8895 EL_DEFAULT, ACTION_EXPLODING, -1
8898 Xboom_2, FALSE, FALSE,
8899 EL_DEFAULT, ACTION_EXPLODING, -1
8902 Znormal, FALSE, FALSE,
8906 Zdynamite, FALSE, FALSE,
8910 Zplayer, FALSE, FALSE,
8914 ZBORDER, FALSE, FALSE,
8924 static struct Mapping_EM_to_RND_player
8933 em_player_mapping_list[] =
8937 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8941 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8945 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8949 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8953 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8957 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8961 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8965 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8969 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
8973 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
8977 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
8981 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
8985 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
8989 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
8993 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
8997 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9001 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9005 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9009 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9013 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9017 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9021 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9025 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9029 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9033 EL_PLAYER_1, ACTION_DEFAULT, -1,
9037 EL_PLAYER_2, ACTION_DEFAULT, -1,
9041 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9045 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9049 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9053 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9057 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9061 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9065 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9069 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9073 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9077 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9081 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9085 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9089 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9093 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9097 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9101 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9105 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9109 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9113 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9117 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9121 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9125 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9129 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9133 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9137 EL_PLAYER_3, ACTION_DEFAULT, -1,
9141 EL_PLAYER_4, ACTION_DEFAULT, -1,
9150 int map_element_RND_to_EM(int element_rnd)
9152 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9153 static boolean mapping_initialized = FALSE;
9155 if (!mapping_initialized)
9159 /* return "Xalpha_quest" for all undefined elements in mapping array */
9160 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9161 mapping_RND_to_EM[i] = Xalpha_quest;
9163 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9164 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9165 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9166 em_object_mapping_list[i].element_em;
9168 mapping_initialized = TRUE;
9171 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9172 return mapping_RND_to_EM[element_rnd];
9174 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9179 int map_element_EM_to_RND(int element_em)
9181 static unsigned short mapping_EM_to_RND[TILE_MAX];
9182 static boolean mapping_initialized = FALSE;
9184 if (!mapping_initialized)
9188 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9189 for (i = 0; i < TILE_MAX; i++)
9190 mapping_EM_to_RND[i] = EL_UNKNOWN;
9192 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9193 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9194 em_object_mapping_list[i].element_rnd;
9196 mapping_initialized = TRUE;
9199 if (element_em >= 0 && element_em < TILE_MAX)
9200 return mapping_EM_to_RND[element_em];
9202 Error(ERR_WARN, "invalid EM level element %d", element_em);
9207 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9209 struct LevelInfo_EM *level_em = level->native_em_level;
9210 struct LEVEL *lev = level_em->lev;
9213 for (i = 0; i < TILE_MAX; i++)
9214 lev->android_array[i] = Xblank;
9216 for (i = 0; i < level->num_android_clone_elements; i++)
9218 int element_rnd = level->android_clone_element[i];
9219 int element_em = map_element_RND_to_EM(element_rnd);
9221 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9222 if (em_object_mapping_list[j].element_rnd == element_rnd)
9223 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9227 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9229 struct LevelInfo_EM *level_em = level->native_em_level;
9230 struct LEVEL *lev = level_em->lev;
9233 level->num_android_clone_elements = 0;
9235 for (i = 0; i < TILE_MAX; i++)
9237 int element_em = lev->android_array[i];
9239 boolean element_found = FALSE;
9241 if (element_em == Xblank)
9244 element_rnd = map_element_EM_to_RND(element_em);
9246 for (j = 0; j < level->num_android_clone_elements; j++)
9247 if (level->android_clone_element[j] == element_rnd)
9248 element_found = TRUE;
9252 level->android_clone_element[level->num_android_clone_elements++] =
9255 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9260 if (level->num_android_clone_elements == 0)
9262 level->num_android_clone_elements = 1;
9263 level->android_clone_element[0] = EL_EMPTY;
9267 int map_direction_RND_to_EM(int direction)
9269 return (direction == MV_UP ? 0 :
9270 direction == MV_RIGHT ? 1 :
9271 direction == MV_DOWN ? 2 :
9272 direction == MV_LEFT ? 3 :
9276 int map_direction_EM_to_RND(int direction)
9278 return (direction == 0 ? MV_UP :
9279 direction == 1 ? MV_RIGHT :
9280 direction == 2 ? MV_DOWN :
9281 direction == 3 ? MV_LEFT :
9285 int map_element_RND_to_SP(int element_rnd)
9287 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9289 if (element_rnd >= EL_SP_START &&
9290 element_rnd <= EL_SP_END)
9291 element_sp = element_rnd - EL_SP_START;
9292 else if (element_rnd == EL_EMPTY_SPACE)
9294 else if (element_rnd == EL_INVISIBLE_WALL)
9300 int map_element_SP_to_RND(int element_sp)
9302 int element_rnd = EL_UNKNOWN;
9304 if (element_sp >= 0x00 &&
9306 element_rnd = EL_SP_START + element_sp;
9307 else if (element_sp == 0x28)
9308 element_rnd = EL_INVISIBLE_WALL;
9313 int map_action_SP_to_RND(int action_sp)
9317 case actActive: return ACTION_ACTIVE;
9318 case actImpact: return ACTION_IMPACT;
9319 case actExploding: return ACTION_EXPLODING;
9320 case actDigging: return ACTION_DIGGING;
9321 case actSnapping: return ACTION_SNAPPING;
9322 case actCollecting: return ACTION_COLLECTING;
9323 case actPassing: return ACTION_PASSING;
9324 case actPushing: return ACTION_PUSHING;
9325 case actDropping: return ACTION_DROPPING;
9327 default: return ACTION_DEFAULT;
9331 int get_next_element(int element)
9335 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9336 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9337 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9338 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9339 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9340 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9341 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9342 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9343 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9344 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9345 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9347 default: return element;
9352 int el_act_dir2img(int element, int action, int direction)
9354 element = GFX_ELEMENT(element);
9356 if (direction == MV_NONE)
9357 return element_info[element].graphic[action];
9359 direction = MV_DIR_TO_BIT(direction);
9361 return element_info[element].direction_graphic[action][direction];
9364 int el_act_dir2img(int element, int action, int direction)
9366 element = GFX_ELEMENT(element);
9367 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9369 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9370 return element_info[element].direction_graphic[action][direction];
9375 static int el_act_dir2crm(int element, int action, int direction)
9377 element = GFX_ELEMENT(element);
9379 if (direction == MV_NONE)
9380 return element_info[element].crumbled[action];
9382 direction = MV_DIR_TO_BIT(direction);
9384 return element_info[element].direction_crumbled[action][direction];
9387 static int el_act_dir2crm(int element, int action, int direction)
9389 element = GFX_ELEMENT(element);
9390 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9392 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9393 return element_info[element].direction_crumbled[action][direction];
9397 int el_act2img(int element, int action)
9399 element = GFX_ELEMENT(element);
9401 return element_info[element].graphic[action];
9404 int el_act2crm(int element, int action)
9406 element = GFX_ELEMENT(element);
9408 return element_info[element].crumbled[action];
9411 int el_dir2img(int element, int direction)
9413 element = GFX_ELEMENT(element);
9415 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9418 int el2baseimg(int element)
9420 return element_info[element].graphic[ACTION_DEFAULT];
9423 int el2img(int element)
9425 element = GFX_ELEMENT(element);
9427 return element_info[element].graphic[ACTION_DEFAULT];
9430 int el2edimg(int element)
9432 element = GFX_ELEMENT(element);
9434 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9437 int el2preimg(int element)
9439 element = GFX_ELEMENT(element);
9441 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9444 int el2panelimg(int element)
9446 element = GFX_ELEMENT(element);
9448 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9451 int font2baseimg(int font_nr)
9453 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9456 int getBeltNrFromBeltElement(int element)
9458 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9459 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9460 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9463 int getBeltNrFromBeltActiveElement(int element)
9465 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9466 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9467 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9470 int getBeltNrFromBeltSwitchElement(int element)
9472 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9473 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9474 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9477 int getBeltDirNrFromBeltElement(int element)
9479 static int belt_base_element[4] =
9481 EL_CONVEYOR_BELT_1_LEFT,
9482 EL_CONVEYOR_BELT_2_LEFT,
9483 EL_CONVEYOR_BELT_3_LEFT,
9484 EL_CONVEYOR_BELT_4_LEFT
9487 int belt_nr = getBeltNrFromBeltElement(element);
9488 int belt_dir_nr = element - belt_base_element[belt_nr];
9490 return (belt_dir_nr % 3);
9493 int getBeltDirNrFromBeltSwitchElement(int element)
9495 static int belt_base_element[4] =
9497 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9498 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9499 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9500 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9503 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9504 int belt_dir_nr = element - belt_base_element[belt_nr];
9506 return (belt_dir_nr % 3);
9509 int getBeltDirFromBeltElement(int element)
9511 static int belt_move_dir[3] =
9518 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9520 return belt_move_dir[belt_dir_nr];
9523 int getBeltDirFromBeltSwitchElement(int element)
9525 static int belt_move_dir[3] =
9532 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9534 return belt_move_dir[belt_dir_nr];
9537 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9539 static int belt_base_element[4] =
9541 EL_CONVEYOR_BELT_1_LEFT,
9542 EL_CONVEYOR_BELT_2_LEFT,
9543 EL_CONVEYOR_BELT_3_LEFT,
9544 EL_CONVEYOR_BELT_4_LEFT
9547 return belt_base_element[belt_nr] + belt_dir_nr;
9550 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9552 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9554 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9557 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9559 static int belt_base_element[4] =
9561 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9562 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9563 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9564 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9567 return belt_base_element[belt_nr] + belt_dir_nr;
9570 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9572 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9574 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9578 boolean getTeamMode_EM()
9580 return game.team_mode;
9583 int getNumActivePlayers_EM()
9586 int num_players = 0;
9590 return (setup.team_mode ? MAX_PLAYERS : 1);
9592 for (i = 0; i < MAX_PLAYERS; i++)
9593 if (tape.player_participates[i])
9596 return (num_players > 1 ? MAX_PLAYERS : 1);
9600 int num_players = 0;
9603 /* when recording game, activate all connected players */
9607 for (i = 0; i < MAX_PLAYERS; i++)
9608 if (tape.player_participates[i])
9616 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9618 int game_frame_delay_value;
9620 game_frame_delay_value =
9621 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9622 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9625 if (tape.playing && tape.warp_forward && !tape.pausing)
9626 game_frame_delay_value = 0;
9628 return game_frame_delay_value;
9631 unsigned int InitRND(int seed)
9633 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9634 return InitEngineRandom_EM(seed);
9635 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9636 return InitEngineRandom_SP(seed);
9638 return InitEngineRandom_RND(seed);
9642 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9643 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9646 inline static int get_effective_element_EM(int tile, int frame_em)
9648 int element = object_mapping[tile].element_rnd;
9649 int action = object_mapping[tile].action;
9650 boolean is_backside = object_mapping[tile].is_backside;
9651 boolean action_removing = (action == ACTION_DIGGING ||
9652 action == ACTION_SNAPPING ||
9653 action == ACTION_COLLECTING);
9659 case Yacid_splash_eB:
9660 case Yacid_splash_wB:
9661 return (frame_em > 5 ? EL_EMPTY : element);
9665 case Ydiamond_stone:
9666 // if (!game.use_native_emc_graphics_engine)
9674 else /* frame_em == 7 */
9678 case Yacid_splash_eB:
9679 case Yacid_splash_wB:
9682 case Yemerald_stone:
9685 case Ydiamond_stone:
9689 case Xdrip_stretchB:
9708 case Xsand_stonein_1:
9709 case Xsand_stonein_2:
9710 case Xsand_stonein_3:
9711 case Xsand_stonein_4:
9715 return (is_backside || action_removing ? EL_EMPTY : element);
9720 inline static boolean check_linear_animation_EM(int tile)
9724 case Xsand_stonesand_1:
9725 case Xsand_stonesand_quickout_1:
9726 case Xsand_sandstone_1:
9727 case Xsand_stonein_1:
9728 case Xsand_stoneout_1:
9748 case Yacid_splash_eB:
9749 case Yacid_splash_wB:
9750 case Yemerald_stone:
9758 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9759 boolean has_crumbled_graphics,
9760 int crumbled, int sync_frame)
9762 /* if element can be crumbled, but certain action graphics are just empty
9763 space (like instantly snapping sand to empty space in 1 frame), do not
9764 treat these empty space graphics as crumbled graphics in EMC engine */
9765 if (crumbled == IMG_EMPTY_SPACE)
9766 has_crumbled_graphics = FALSE;
9768 if (has_crumbled_graphics)
9770 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9771 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9772 g_crumbled->anim_delay,
9773 g_crumbled->anim_mode,
9774 g_crumbled->anim_start_frame,
9777 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9778 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9780 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9782 g_em->has_crumbled_graphics = TRUE;
9786 g_em->crumbled_bitmap = NULL;
9787 g_em->crumbled_src_x = 0;
9788 g_em->crumbled_src_y = 0;
9789 g_em->crumbled_border_size = 0;
9791 g_em->has_crumbled_graphics = FALSE;
9795 void ResetGfxAnimation_EM(int x, int y, int tile)
9800 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9801 int tile, int frame_em, int x, int y)
9803 int action = object_mapping[tile].action;
9805 int direction = object_mapping[tile].direction;
9806 int effective_element = get_effective_element_EM(tile, frame_em);
9807 int graphic = (direction == MV_NONE ?
9808 el_act2img(effective_element, action) :
9809 el_act_dir2img(effective_element, action, direction));
9810 struct GraphicInfo *g = &graphic_info[graphic];
9813 boolean action_removing = (action == ACTION_DIGGING ||
9814 action == ACTION_SNAPPING ||
9815 action == ACTION_COLLECTING);
9816 boolean action_moving = (action == ACTION_FALLING ||
9817 action == ACTION_MOVING ||
9818 action == ACTION_PUSHING ||
9819 action == ACTION_EATING ||
9820 action == ACTION_FILLING ||
9821 action == ACTION_EMPTYING);
9822 boolean action_falling = (action == ACTION_FALLING ||
9823 action == ACTION_FILLING ||
9824 action == ACTION_EMPTYING);
9826 /* special case: graphic uses "2nd movement tile" and has defined
9827 7 frames for movement animation (or less) => use default graphic
9828 for last (8th) frame which ends the movement animation */
9829 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9831 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9832 graphic = (direction == MV_NONE ?
9833 el_act2img(effective_element, action) :
9834 el_act_dir2img(effective_element, action, direction));
9836 g = &graphic_info[graphic];
9840 if (tile == Xsand_stonesand_1 ||
9841 tile == Xsand_stonesand_2 ||
9842 tile == Xsand_stonesand_3 ||
9843 tile == Xsand_stonesand_4)
9844 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9848 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9852 // printf("::: resetting... [%d]\n", tile);
9855 if (action_removing || check_linear_animation_EM(tile))
9857 GfxFrame[x][y] = frame_em;
9859 // printf("::: resetting... [%d]\n", tile);
9862 else if (action_moving)
9864 boolean is_backside = object_mapping[tile].is_backside;
9868 int direction = object_mapping[tile].direction;
9869 int move_dir = (action_falling ? MV_DOWN : direction);
9874 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9875 if (g->double_movement && frame_em == 0)
9879 // printf("::: resetting... [%d]\n", tile);
9883 if (move_dir == MV_LEFT)
9884 GfxFrame[x - 1][y] = GfxFrame[x][y];
9885 else if (move_dir == MV_RIGHT)
9886 GfxFrame[x + 1][y] = GfxFrame[x][y];
9887 else if (move_dir == MV_UP)
9888 GfxFrame[x][y - 1] = GfxFrame[x][y];
9889 else if (move_dir == MV_DOWN)
9890 GfxFrame[x][y + 1] = GfxFrame[x][y];
9897 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9898 if (tile == Xsand_stonesand_quickout_1 ||
9899 tile == Xsand_stonesand_quickout_2)
9904 if (tile == Xsand_stonesand_1 ||
9905 tile == Xsand_stonesand_2 ||
9906 tile == Xsand_stonesand_3 ||
9907 tile == Xsand_stonesand_4)
9908 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9912 if (graphic_info[graphic].anim_global_sync)
9913 sync_frame = FrameCounter;
9914 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9915 sync_frame = GfxFrame[x][y];
9917 sync_frame = 0; /* playfield border (pseudo steel) */
9919 SetRandomAnimationValue(x, y);
9921 int frame = getAnimationFrame(g->anim_frames,
9924 g->anim_start_frame,
9927 g_em->unique_identifier =
9928 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9932 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9933 int tile, int frame_em, int x, int y)
9935 int action = object_mapping[tile].action;
9936 int direction = object_mapping[tile].direction;
9937 boolean is_backside = object_mapping[tile].is_backside;
9938 int effective_element = get_effective_element_EM(tile, frame_em);
9940 int effective_action = action;
9942 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9944 int graphic = (direction == MV_NONE ?
9945 el_act2img(effective_element, effective_action) :
9946 el_act_dir2img(effective_element, effective_action,
9948 int crumbled = (direction == MV_NONE ?
9949 el_act2crm(effective_element, effective_action) :
9950 el_act_dir2crm(effective_element, effective_action,
9952 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9953 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9954 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9955 struct GraphicInfo *g = &graphic_info[graphic];
9957 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9961 /* special case: graphic uses "2nd movement tile" and has defined
9962 7 frames for movement animation (or less) => use default graphic
9963 for last (8th) frame which ends the movement animation */
9964 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9966 effective_action = ACTION_DEFAULT;
9967 graphic = (direction == MV_NONE ?
9968 el_act2img(effective_element, effective_action) :
9969 el_act_dir2img(effective_element, effective_action,
9971 crumbled = (direction == MV_NONE ?
9972 el_act2crm(effective_element, effective_action) :
9973 el_act_dir2crm(effective_element, effective_action,
9976 g = &graphic_info[graphic];
9986 if (frame_em == 0) /* reset animation frame for certain elements */
9988 if (check_linear_animation_EM(tile))
9993 if (graphic_info[graphic].anim_global_sync)
9994 sync_frame = FrameCounter;
9995 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9996 sync_frame = GfxFrame[x][y];
9998 sync_frame = 0; /* playfield border (pseudo steel) */
10000 SetRandomAnimationValue(x, y);
10005 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10006 i == Xdrip_stretchB ? 7 :
10007 i == Ydrip_s2 ? j + 8 :
10008 i == Ydrip_s2B ? j + 8 :
10010 i == Xacid_2 ? 10 :
10011 i == Xacid_3 ? 20 :
10012 i == Xacid_4 ? 30 :
10013 i == Xacid_5 ? 40 :
10014 i == Xacid_6 ? 50 :
10015 i == Xacid_7 ? 60 :
10016 i == Xacid_8 ? 70 :
10017 i == Xfake_acid_1 ? 0 :
10018 i == Xfake_acid_2 ? 10 :
10019 i == Xfake_acid_3 ? 20 :
10020 i == Xfake_acid_4 ? 30 :
10021 i == Xfake_acid_5 ? 40 :
10022 i == Xfake_acid_6 ? 50 :
10023 i == Xfake_acid_7 ? 60 :
10024 i == Xfake_acid_8 ? 70 :
10026 i == Xball_2B ? j + 8 :
10027 i == Yball_eat ? j + 1 :
10028 i == Ykey_1_eat ? j + 1 :
10029 i == Ykey_2_eat ? j + 1 :
10030 i == Ykey_3_eat ? j + 1 :
10031 i == Ykey_4_eat ? j + 1 :
10032 i == Ykey_5_eat ? j + 1 :
10033 i == Ykey_6_eat ? j + 1 :
10034 i == Ykey_7_eat ? j + 1 :
10035 i == Ykey_8_eat ? j + 1 :
10036 i == Ylenses_eat ? j + 1 :
10037 i == Ymagnify_eat ? j + 1 :
10038 i == Ygrass_eat ? j + 1 :
10039 i == Ydirt_eat ? j + 1 :
10040 i == Xamoeba_1 ? 0 :
10041 i == Xamoeba_2 ? 1 :
10042 i == Xamoeba_3 ? 2 :
10043 i == Xamoeba_4 ? 3 :
10044 i == Xamoeba_5 ? 0 :
10045 i == Xamoeba_6 ? 1 :
10046 i == Xamoeba_7 ? 2 :
10047 i == Xamoeba_8 ? 3 :
10048 i == Xexit_2 ? j + 8 :
10049 i == Xexit_3 ? j + 16 :
10050 i == Xdynamite_1 ? 0 :
10051 i == Xdynamite_2 ? 8 :
10052 i == Xdynamite_3 ? 16 :
10053 i == Xdynamite_4 ? 24 :
10054 i == Xsand_stonein_1 ? j + 1 :
10055 i == Xsand_stonein_2 ? j + 9 :
10056 i == Xsand_stonein_3 ? j + 17 :
10057 i == Xsand_stonein_4 ? j + 25 :
10058 i == Xsand_stoneout_1 && j == 0 ? 0 :
10059 i == Xsand_stoneout_1 && j == 1 ? 0 :
10060 i == Xsand_stoneout_1 && j == 2 ? 1 :
10061 i == Xsand_stoneout_1 && j == 3 ? 2 :
10062 i == Xsand_stoneout_1 && j == 4 ? 2 :
10063 i == Xsand_stoneout_1 && j == 5 ? 3 :
10064 i == Xsand_stoneout_1 && j == 6 ? 4 :
10065 i == Xsand_stoneout_1 && j == 7 ? 4 :
10066 i == Xsand_stoneout_2 && j == 0 ? 5 :
10067 i == Xsand_stoneout_2 && j == 1 ? 6 :
10068 i == Xsand_stoneout_2 && j == 2 ? 7 :
10069 i == Xsand_stoneout_2 && j == 3 ? 8 :
10070 i == Xsand_stoneout_2 && j == 4 ? 9 :
10071 i == Xsand_stoneout_2 && j == 5 ? 11 :
10072 i == Xsand_stoneout_2 && j == 6 ? 13 :
10073 i == Xsand_stoneout_2 && j == 7 ? 15 :
10074 i == Xboom_bug && j == 1 ? 2 :
10075 i == Xboom_bug && j == 2 ? 2 :
10076 i == Xboom_bug && j == 3 ? 4 :
10077 i == Xboom_bug && j == 4 ? 4 :
10078 i == Xboom_bug && j == 5 ? 2 :
10079 i == Xboom_bug && j == 6 ? 2 :
10080 i == Xboom_bug && j == 7 ? 0 :
10081 i == Xboom_bomb && j == 1 ? 2 :
10082 i == Xboom_bomb && j == 2 ? 2 :
10083 i == Xboom_bomb && j == 3 ? 4 :
10084 i == Xboom_bomb && j == 4 ? 4 :
10085 i == Xboom_bomb && j == 5 ? 2 :
10086 i == Xboom_bomb && j == 6 ? 2 :
10087 i == Xboom_bomb && j == 7 ? 0 :
10088 i == Xboom_android && j == 7 ? 6 :
10089 i == Xboom_1 && j == 1 ? 2 :
10090 i == Xboom_1 && j == 2 ? 2 :
10091 i == Xboom_1 && j == 3 ? 4 :
10092 i == Xboom_1 && j == 4 ? 4 :
10093 i == Xboom_1 && j == 5 ? 6 :
10094 i == Xboom_1 && j == 6 ? 6 :
10095 i == Xboom_1 && j == 7 ? 8 :
10096 i == Xboom_2 && j == 0 ? 8 :
10097 i == Xboom_2 && j == 1 ? 8 :
10098 i == Xboom_2 && j == 2 ? 10 :
10099 i == Xboom_2 && j == 3 ? 10 :
10100 i == Xboom_2 && j == 4 ? 10 :
10101 i == Xboom_2 && j == 5 ? 12 :
10102 i == Xboom_2 && j == 6 ? 12 :
10103 i == Xboom_2 && j == 7 ? 12 :
10105 special_animation && j == 4 ? 3 :
10106 effective_action != action ? 0 :
10112 int xxx_effective_action;
10113 int xxx_has_action_graphics;
10116 int element = object_mapping[i].element_rnd;
10117 int action = object_mapping[i].action;
10118 int direction = object_mapping[i].direction;
10119 boolean is_backside = object_mapping[i].is_backside;
10121 boolean action_removing = (action == ACTION_DIGGING ||
10122 action == ACTION_SNAPPING ||
10123 action == ACTION_COLLECTING);
10125 boolean action_exploding = ((action == ACTION_EXPLODING ||
10126 action == ACTION_SMASHED_BY_ROCK ||
10127 action == ACTION_SMASHED_BY_SPRING) &&
10128 element != EL_DIAMOND);
10129 boolean action_active = (action == ACTION_ACTIVE);
10130 boolean action_other = (action == ACTION_OTHER);
10134 int effective_element = get_effective_element_EM(i, j);
10136 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10137 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10139 i == Xdrip_stretch ? element :
10140 i == Xdrip_stretchB ? element :
10141 i == Ydrip_s1 ? element :
10142 i == Ydrip_s1B ? element :
10143 i == Xball_1B ? element :
10144 i == Xball_2 ? element :
10145 i == Xball_2B ? element :
10146 i == Yball_eat ? element :
10147 i == Ykey_1_eat ? element :
10148 i == Ykey_2_eat ? element :
10149 i == Ykey_3_eat ? element :
10150 i == Ykey_4_eat ? element :
10151 i == Ykey_5_eat ? element :
10152 i == Ykey_6_eat ? element :
10153 i == Ykey_7_eat ? element :
10154 i == Ykey_8_eat ? element :
10155 i == Ylenses_eat ? element :
10156 i == Ymagnify_eat ? element :
10157 i == Ygrass_eat ? element :
10158 i == Ydirt_eat ? element :
10159 i == Yemerald_stone ? EL_EMERALD :
10160 i == Ydiamond_stone ? EL_ROCK :
10161 i == Xsand_stonein_1 ? element :
10162 i == Xsand_stonein_2 ? element :
10163 i == Xsand_stonein_3 ? element :
10164 i == Xsand_stonein_4 ? element :
10165 is_backside ? EL_EMPTY :
10166 action_removing ? EL_EMPTY :
10169 int effective_action = (j < 7 ? action :
10170 i == Xdrip_stretch ? action :
10171 i == Xdrip_stretchB ? action :
10172 i == Ydrip_s1 ? action :
10173 i == Ydrip_s1B ? action :
10174 i == Xball_1B ? action :
10175 i == Xball_2 ? action :
10176 i == Xball_2B ? action :
10177 i == Yball_eat ? action :
10178 i == Ykey_1_eat ? action :
10179 i == Ykey_2_eat ? action :
10180 i == Ykey_3_eat ? action :
10181 i == Ykey_4_eat ? action :
10182 i == Ykey_5_eat ? action :
10183 i == Ykey_6_eat ? action :
10184 i == Ykey_7_eat ? action :
10185 i == Ykey_8_eat ? action :
10186 i == Ylenses_eat ? action :
10187 i == Ymagnify_eat ? action :
10188 i == Ygrass_eat ? action :
10189 i == Ydirt_eat ? action :
10190 i == Xsand_stonein_1 ? action :
10191 i == Xsand_stonein_2 ? action :
10192 i == Xsand_stonein_3 ? action :
10193 i == Xsand_stonein_4 ? action :
10194 i == Xsand_stoneout_1 ? action :
10195 i == Xsand_stoneout_2 ? action :
10196 i == Xboom_android ? ACTION_EXPLODING :
10197 action_exploding ? ACTION_EXPLODING :
10198 action_active ? action :
10199 action_other ? action :
10201 int graphic = (el_act_dir2img(effective_element, effective_action,
10203 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10205 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10206 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10207 boolean has_action_graphics = (graphic != base_graphic);
10208 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10209 struct GraphicInfo *g = &graphic_info[graphic];
10211 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10213 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10214 Bitmap *src_bitmap;
10216 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10217 boolean special_animation = (action != ACTION_DEFAULT &&
10218 g->anim_frames == 3 &&
10219 g->anim_delay == 2 &&
10220 g->anim_mode & ANIM_LINEAR);
10221 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10222 i == Xdrip_stretchB ? 7 :
10223 i == Ydrip_s2 ? j + 8 :
10224 i == Ydrip_s2B ? j + 8 :
10226 i == Xacid_2 ? 10 :
10227 i == Xacid_3 ? 20 :
10228 i == Xacid_4 ? 30 :
10229 i == Xacid_5 ? 40 :
10230 i == Xacid_6 ? 50 :
10231 i == Xacid_7 ? 60 :
10232 i == Xacid_8 ? 70 :
10233 i == Xfake_acid_1 ? 0 :
10234 i == Xfake_acid_2 ? 10 :
10235 i == Xfake_acid_3 ? 20 :
10236 i == Xfake_acid_4 ? 30 :
10237 i == Xfake_acid_5 ? 40 :
10238 i == Xfake_acid_6 ? 50 :
10239 i == Xfake_acid_7 ? 60 :
10240 i == Xfake_acid_8 ? 70 :
10242 i == Xball_2B ? j + 8 :
10243 i == Yball_eat ? j + 1 :
10244 i == Ykey_1_eat ? j + 1 :
10245 i == Ykey_2_eat ? j + 1 :
10246 i == Ykey_3_eat ? j + 1 :
10247 i == Ykey_4_eat ? j + 1 :
10248 i == Ykey_5_eat ? j + 1 :
10249 i == Ykey_6_eat ? j + 1 :
10250 i == Ykey_7_eat ? j + 1 :
10251 i == Ykey_8_eat ? j + 1 :
10252 i == Ylenses_eat ? j + 1 :
10253 i == Ymagnify_eat ? j + 1 :
10254 i == Ygrass_eat ? j + 1 :
10255 i == Ydirt_eat ? j + 1 :
10256 i == Xamoeba_1 ? 0 :
10257 i == Xamoeba_2 ? 1 :
10258 i == Xamoeba_3 ? 2 :
10259 i == Xamoeba_4 ? 3 :
10260 i == Xamoeba_5 ? 0 :
10261 i == Xamoeba_6 ? 1 :
10262 i == Xamoeba_7 ? 2 :
10263 i == Xamoeba_8 ? 3 :
10264 i == Xexit_2 ? j + 8 :
10265 i == Xexit_3 ? j + 16 :
10266 i == Xdynamite_1 ? 0 :
10267 i == Xdynamite_2 ? 8 :
10268 i == Xdynamite_3 ? 16 :
10269 i == Xdynamite_4 ? 24 :
10270 i == Xsand_stonein_1 ? j + 1 :
10271 i == Xsand_stonein_2 ? j + 9 :
10272 i == Xsand_stonein_3 ? j + 17 :
10273 i == Xsand_stonein_4 ? j + 25 :
10274 i == Xsand_stoneout_1 && j == 0 ? 0 :
10275 i == Xsand_stoneout_1 && j == 1 ? 0 :
10276 i == Xsand_stoneout_1 && j == 2 ? 1 :
10277 i == Xsand_stoneout_1 && j == 3 ? 2 :
10278 i == Xsand_stoneout_1 && j == 4 ? 2 :
10279 i == Xsand_stoneout_1 && j == 5 ? 3 :
10280 i == Xsand_stoneout_1 && j == 6 ? 4 :
10281 i == Xsand_stoneout_1 && j == 7 ? 4 :
10282 i == Xsand_stoneout_2 && j == 0 ? 5 :
10283 i == Xsand_stoneout_2 && j == 1 ? 6 :
10284 i == Xsand_stoneout_2 && j == 2 ? 7 :
10285 i == Xsand_stoneout_2 && j == 3 ? 8 :
10286 i == Xsand_stoneout_2 && j == 4 ? 9 :
10287 i == Xsand_stoneout_2 && j == 5 ? 11 :
10288 i == Xsand_stoneout_2 && j == 6 ? 13 :
10289 i == Xsand_stoneout_2 && j == 7 ? 15 :
10290 i == Xboom_bug && j == 1 ? 2 :
10291 i == Xboom_bug && j == 2 ? 2 :
10292 i == Xboom_bug && j == 3 ? 4 :
10293 i == Xboom_bug && j == 4 ? 4 :
10294 i == Xboom_bug && j == 5 ? 2 :
10295 i == Xboom_bug && j == 6 ? 2 :
10296 i == Xboom_bug && j == 7 ? 0 :
10297 i == Xboom_bomb && j == 1 ? 2 :
10298 i == Xboom_bomb && j == 2 ? 2 :
10299 i == Xboom_bomb && j == 3 ? 4 :
10300 i == Xboom_bomb && j == 4 ? 4 :
10301 i == Xboom_bomb && j == 5 ? 2 :
10302 i == Xboom_bomb && j == 6 ? 2 :
10303 i == Xboom_bomb && j == 7 ? 0 :
10304 i == Xboom_android && j == 7 ? 6 :
10305 i == Xboom_1 && j == 1 ? 2 :
10306 i == Xboom_1 && j == 2 ? 2 :
10307 i == Xboom_1 && j == 3 ? 4 :
10308 i == Xboom_1 && j == 4 ? 4 :
10309 i == Xboom_1 && j == 5 ? 6 :
10310 i == Xboom_1 && j == 6 ? 6 :
10311 i == Xboom_1 && j == 7 ? 8 :
10312 i == Xboom_2 && j == 0 ? 8 :
10313 i == Xboom_2 && j == 1 ? 8 :
10314 i == Xboom_2 && j == 2 ? 10 :
10315 i == Xboom_2 && j == 3 ? 10 :
10316 i == Xboom_2 && j == 4 ? 10 :
10317 i == Xboom_2 && j == 5 ? 12 :
10318 i == Xboom_2 && j == 6 ? 12 :
10319 i == Xboom_2 && j == 7 ? 12 :
10320 special_animation && j == 4 ? 3 :
10321 effective_action != action ? 0 :
10324 xxx_effective_action = effective_action;
10325 xxx_has_action_graphics = has_action_graphics;
10330 int frame = getAnimationFrame(g->anim_frames,
10333 g->anim_start_frame,
10347 int old_src_x = g_em->src_x;
10348 int old_src_y = g_em->src_y;
10352 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10353 g->double_movement && is_backside);
10355 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10356 &g_em->src_x, &g_em->src_y, FALSE);
10361 if (tile == Ydiamond_stone)
10362 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10367 g->anim_start_frame,
10370 g_em->src_x, g_em->src_y,
10371 g_em->src_offset_x, g_em->src_offset_y,
10372 g_em->dst_offset_x, g_em->dst_offset_y,
10384 if (graphic == IMG_BUG_MOVING_RIGHT)
10385 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10386 g->double_movement, is_backside,
10387 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10395 g_em->src_offset_x = 0;
10396 g_em->src_offset_y = 0;
10397 g_em->dst_offset_x = 0;
10398 g_em->dst_offset_y = 0;
10399 g_em->width = TILEX;
10400 g_em->height = TILEY;
10402 g_em->preserve_background = FALSE;
10405 /* (updating the "crumbled" graphic definitions is probably not really needed,
10406 as animations for crumbled graphics can't be longer than one EMC cycle) */
10408 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10413 g_em->crumbled_bitmap = NULL;
10414 g_em->crumbled_src_x = 0;
10415 g_em->crumbled_src_y = 0;
10417 g_em->has_crumbled_graphics = FALSE;
10419 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10421 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10422 g_crumbled->anim_delay,
10423 g_crumbled->anim_mode,
10424 g_crumbled->anim_start_frame,
10427 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10428 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10430 g_em->has_crumbled_graphics = TRUE;
10436 int effective_action = xxx_effective_action;
10437 int has_action_graphics = xxx_has_action_graphics;
10439 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10440 effective_action == ACTION_MOVING ||
10441 effective_action == ACTION_PUSHING ||
10442 effective_action == ACTION_EATING)) ||
10443 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10444 effective_action == ACTION_EMPTYING)))
10447 (effective_action == ACTION_FALLING ||
10448 effective_action == ACTION_FILLING ||
10449 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10450 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10451 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10452 int num_steps = (i == Ydrip_s1 ? 16 :
10453 i == Ydrip_s1B ? 16 :
10454 i == Ydrip_s2 ? 16 :
10455 i == Ydrip_s2B ? 16 :
10456 i == Xsand_stonein_1 ? 32 :
10457 i == Xsand_stonein_2 ? 32 :
10458 i == Xsand_stonein_3 ? 32 :
10459 i == Xsand_stonein_4 ? 32 :
10460 i == Xsand_stoneout_1 ? 16 :
10461 i == Xsand_stoneout_2 ? 16 : 8);
10462 int cx = ABS(dx) * (TILEX / num_steps);
10463 int cy = ABS(dy) * (TILEY / num_steps);
10464 int step_frame = (i == Ydrip_s2 ? j + 8 :
10465 i == Ydrip_s2B ? j + 8 :
10466 i == Xsand_stonein_2 ? j + 8 :
10467 i == Xsand_stonein_3 ? j + 16 :
10468 i == Xsand_stonein_4 ? j + 24 :
10469 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10470 int step = (is_backside ? step_frame : num_steps - step_frame);
10472 if (is_backside) /* tile where movement starts */
10474 if (dx < 0 || dy < 0)
10476 g_em->src_offset_x = cx * step;
10477 g_em->src_offset_y = cy * step;
10481 g_em->dst_offset_x = cx * step;
10482 g_em->dst_offset_y = cy * step;
10485 else /* tile where movement ends */
10487 if (dx < 0 || dy < 0)
10489 g_em->dst_offset_x = cx * step;
10490 g_em->dst_offset_y = cy * step;
10494 g_em->src_offset_x = cx * step;
10495 g_em->src_offset_y = cy * step;
10499 g_em->width = TILEX - cx * step;
10500 g_em->height = TILEY - cy * step;
10503 /* create unique graphic identifier to decide if tile must be redrawn */
10504 /* bit 31 - 16 (16 bit): EM style graphic
10505 bit 15 - 12 ( 4 bit): EM style frame
10506 bit 11 - 6 ( 6 bit): graphic width
10507 bit 5 - 0 ( 6 bit): graphic height */
10508 g_em->unique_identifier =
10509 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10515 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10516 int player_nr, int anim, int frame_em)
10518 int element = player_mapping[player_nr][anim].element_rnd;
10519 int action = player_mapping[player_nr][anim].action;
10520 int direction = player_mapping[player_nr][anim].direction;
10521 int graphic = (direction == MV_NONE ?
10522 el_act2img(element, action) :
10523 el_act_dir2img(element, action, direction));
10524 struct GraphicInfo *g = &graphic_info[graphic];
10527 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10529 stored_player[player_nr].StepFrame = frame_em;
10531 sync_frame = stored_player[player_nr].Frame;
10533 int frame = getAnimationFrame(g->anim_frames,
10536 g->anim_start_frame,
10539 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10540 &g_em->src_x, &g_em->src_y, FALSE);
10543 printf("::: %d: %d, %d [%d]\n",
10545 stored_player[player_nr].Frame,
10546 stored_player[player_nr].StepFrame,
10551 void InitGraphicInfo_EM(void)
10554 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10555 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10560 int num_em_gfx_errors = 0;
10562 if (graphic_info_em_object[0][0].bitmap == NULL)
10564 /* EM graphics not yet initialized in em_open_all() */
10569 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10572 /* always start with reliable default values */
10573 for (i = 0; i < TILE_MAX; i++)
10575 object_mapping[i].element_rnd = EL_UNKNOWN;
10576 object_mapping[i].is_backside = FALSE;
10577 object_mapping[i].action = ACTION_DEFAULT;
10578 object_mapping[i].direction = MV_NONE;
10581 /* always start with reliable default values */
10582 for (p = 0; p < MAX_PLAYERS; p++)
10584 for (i = 0; i < SPR_MAX; i++)
10586 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10587 player_mapping[p][i].action = ACTION_DEFAULT;
10588 player_mapping[p][i].direction = MV_NONE;
10592 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10594 int e = em_object_mapping_list[i].element_em;
10596 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10597 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10599 if (em_object_mapping_list[i].action != -1)
10600 object_mapping[e].action = em_object_mapping_list[i].action;
10602 if (em_object_mapping_list[i].direction != -1)
10603 object_mapping[e].direction =
10604 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10607 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10609 int a = em_player_mapping_list[i].action_em;
10610 int p = em_player_mapping_list[i].player_nr;
10612 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10614 if (em_player_mapping_list[i].action != -1)
10615 player_mapping[p][a].action = em_player_mapping_list[i].action;
10617 if (em_player_mapping_list[i].direction != -1)
10618 player_mapping[p][a].direction =
10619 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10622 for (i = 0; i < TILE_MAX; i++)
10624 int element = object_mapping[i].element_rnd;
10625 int action = object_mapping[i].action;
10626 int direction = object_mapping[i].direction;
10627 boolean is_backside = object_mapping[i].is_backside;
10629 boolean action_removing = (action == ACTION_DIGGING ||
10630 action == ACTION_SNAPPING ||
10631 action == ACTION_COLLECTING);
10633 boolean action_exploding = ((action == ACTION_EXPLODING ||
10634 action == ACTION_SMASHED_BY_ROCK ||
10635 action == ACTION_SMASHED_BY_SPRING) &&
10636 element != EL_DIAMOND);
10637 boolean action_active = (action == ACTION_ACTIVE);
10638 boolean action_other = (action == ACTION_OTHER);
10640 for (j = 0; j < 8; j++)
10643 int effective_element = get_effective_element_EM(i, j);
10645 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10646 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10648 i == Xdrip_stretch ? element :
10649 i == Xdrip_stretchB ? element :
10650 i == Ydrip_s1 ? element :
10651 i == Ydrip_s1B ? element :
10652 i == Xball_1B ? element :
10653 i == Xball_2 ? element :
10654 i == Xball_2B ? element :
10655 i == Yball_eat ? element :
10656 i == Ykey_1_eat ? element :
10657 i == Ykey_2_eat ? element :
10658 i == Ykey_3_eat ? element :
10659 i == Ykey_4_eat ? element :
10660 i == Ykey_5_eat ? element :
10661 i == Ykey_6_eat ? element :
10662 i == Ykey_7_eat ? element :
10663 i == Ykey_8_eat ? element :
10664 i == Ylenses_eat ? element :
10665 i == Ymagnify_eat ? element :
10666 i == Ygrass_eat ? element :
10667 i == Ydirt_eat ? element :
10668 i == Yemerald_stone ? EL_EMERALD :
10669 i == Ydiamond_stone ? EL_ROCK :
10670 i == Xsand_stonein_1 ? element :
10671 i == Xsand_stonein_2 ? element :
10672 i == Xsand_stonein_3 ? element :
10673 i == Xsand_stonein_4 ? element :
10674 is_backside ? EL_EMPTY :
10675 action_removing ? EL_EMPTY :
10678 int effective_action = (j < 7 ? action :
10679 i == Xdrip_stretch ? action :
10680 i == Xdrip_stretchB ? action :
10681 i == Ydrip_s1 ? action :
10682 i == Ydrip_s1B ? action :
10683 i == Xball_1B ? action :
10684 i == Xball_2 ? action :
10685 i == Xball_2B ? action :
10686 i == Yball_eat ? action :
10687 i == Ykey_1_eat ? action :
10688 i == Ykey_2_eat ? action :
10689 i == Ykey_3_eat ? action :
10690 i == Ykey_4_eat ? action :
10691 i == Ykey_5_eat ? action :
10692 i == Ykey_6_eat ? action :
10693 i == Ykey_7_eat ? action :
10694 i == Ykey_8_eat ? action :
10695 i == Ylenses_eat ? action :
10696 i == Ymagnify_eat ? action :
10697 i == Ygrass_eat ? action :
10698 i == Ydirt_eat ? action :
10699 i == Xsand_stonein_1 ? action :
10700 i == Xsand_stonein_2 ? action :
10701 i == Xsand_stonein_3 ? action :
10702 i == Xsand_stonein_4 ? action :
10703 i == Xsand_stoneout_1 ? action :
10704 i == Xsand_stoneout_2 ? action :
10705 i == Xboom_android ? ACTION_EXPLODING :
10706 action_exploding ? ACTION_EXPLODING :
10707 action_active ? action :
10708 action_other ? action :
10710 int graphic = (el_act_dir2img(effective_element, effective_action,
10712 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10714 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10715 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10716 boolean has_action_graphics = (graphic != base_graphic);
10717 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10718 struct GraphicInfo *g = &graphic_info[graphic];
10720 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10722 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10723 Bitmap *src_bitmap;
10725 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10726 boolean special_animation = (action != ACTION_DEFAULT &&
10727 g->anim_frames == 3 &&
10728 g->anim_delay == 2 &&
10729 g->anim_mode & ANIM_LINEAR);
10730 int sync_frame = (i == Xdrip_stretch ? 7 :
10731 i == Xdrip_stretchB ? 7 :
10732 i == Ydrip_s2 ? j + 8 :
10733 i == Ydrip_s2B ? j + 8 :
10735 i == Xacid_2 ? 10 :
10736 i == Xacid_3 ? 20 :
10737 i == Xacid_4 ? 30 :
10738 i == Xacid_5 ? 40 :
10739 i == Xacid_6 ? 50 :
10740 i == Xacid_7 ? 60 :
10741 i == Xacid_8 ? 70 :
10742 i == Xfake_acid_1 ? 0 :
10743 i == Xfake_acid_2 ? 10 :
10744 i == Xfake_acid_3 ? 20 :
10745 i == Xfake_acid_4 ? 30 :
10746 i == Xfake_acid_5 ? 40 :
10747 i == Xfake_acid_6 ? 50 :
10748 i == Xfake_acid_7 ? 60 :
10749 i == Xfake_acid_8 ? 70 :
10751 i == Xball_2B ? j + 8 :
10752 i == Yball_eat ? j + 1 :
10753 i == Ykey_1_eat ? j + 1 :
10754 i == Ykey_2_eat ? j + 1 :
10755 i == Ykey_3_eat ? j + 1 :
10756 i == Ykey_4_eat ? j + 1 :
10757 i == Ykey_5_eat ? j + 1 :
10758 i == Ykey_6_eat ? j + 1 :
10759 i == Ykey_7_eat ? j + 1 :
10760 i == Ykey_8_eat ? j + 1 :
10761 i == Ylenses_eat ? j + 1 :
10762 i == Ymagnify_eat ? j + 1 :
10763 i == Ygrass_eat ? j + 1 :
10764 i == Ydirt_eat ? j + 1 :
10765 i == Xamoeba_1 ? 0 :
10766 i == Xamoeba_2 ? 1 :
10767 i == Xamoeba_3 ? 2 :
10768 i == Xamoeba_4 ? 3 :
10769 i == Xamoeba_5 ? 0 :
10770 i == Xamoeba_6 ? 1 :
10771 i == Xamoeba_7 ? 2 :
10772 i == Xamoeba_8 ? 3 :
10773 i == Xexit_2 ? j + 8 :
10774 i == Xexit_3 ? j + 16 :
10775 i == Xdynamite_1 ? 0 :
10776 i == Xdynamite_2 ? 8 :
10777 i == Xdynamite_3 ? 16 :
10778 i == Xdynamite_4 ? 24 :
10779 i == Xsand_stonein_1 ? j + 1 :
10780 i == Xsand_stonein_2 ? j + 9 :
10781 i == Xsand_stonein_3 ? j + 17 :
10782 i == Xsand_stonein_4 ? j + 25 :
10783 i == Xsand_stoneout_1 && j == 0 ? 0 :
10784 i == Xsand_stoneout_1 && j == 1 ? 0 :
10785 i == Xsand_stoneout_1 && j == 2 ? 1 :
10786 i == Xsand_stoneout_1 && j == 3 ? 2 :
10787 i == Xsand_stoneout_1 && j == 4 ? 2 :
10788 i == Xsand_stoneout_1 && j == 5 ? 3 :
10789 i == Xsand_stoneout_1 && j == 6 ? 4 :
10790 i == Xsand_stoneout_1 && j == 7 ? 4 :
10791 i == Xsand_stoneout_2 && j == 0 ? 5 :
10792 i == Xsand_stoneout_2 && j == 1 ? 6 :
10793 i == Xsand_stoneout_2 && j == 2 ? 7 :
10794 i == Xsand_stoneout_2 && j == 3 ? 8 :
10795 i == Xsand_stoneout_2 && j == 4 ? 9 :
10796 i == Xsand_stoneout_2 && j == 5 ? 11 :
10797 i == Xsand_stoneout_2 && j == 6 ? 13 :
10798 i == Xsand_stoneout_2 && j == 7 ? 15 :
10799 i == Xboom_bug && j == 1 ? 2 :
10800 i == Xboom_bug && j == 2 ? 2 :
10801 i == Xboom_bug && j == 3 ? 4 :
10802 i == Xboom_bug && j == 4 ? 4 :
10803 i == Xboom_bug && j == 5 ? 2 :
10804 i == Xboom_bug && j == 6 ? 2 :
10805 i == Xboom_bug && j == 7 ? 0 :
10806 i == Xboom_bomb && j == 1 ? 2 :
10807 i == Xboom_bomb && j == 2 ? 2 :
10808 i == Xboom_bomb && j == 3 ? 4 :
10809 i == Xboom_bomb && j == 4 ? 4 :
10810 i == Xboom_bomb && j == 5 ? 2 :
10811 i == Xboom_bomb && j == 6 ? 2 :
10812 i == Xboom_bomb && j == 7 ? 0 :
10813 i == Xboom_android && j == 7 ? 6 :
10814 i == Xboom_1 && j == 1 ? 2 :
10815 i == Xboom_1 && j == 2 ? 2 :
10816 i == Xboom_1 && j == 3 ? 4 :
10817 i == Xboom_1 && j == 4 ? 4 :
10818 i == Xboom_1 && j == 5 ? 6 :
10819 i == Xboom_1 && j == 6 ? 6 :
10820 i == Xboom_1 && j == 7 ? 8 :
10821 i == Xboom_2 && j == 0 ? 8 :
10822 i == Xboom_2 && j == 1 ? 8 :
10823 i == Xboom_2 && j == 2 ? 10 :
10824 i == Xboom_2 && j == 3 ? 10 :
10825 i == Xboom_2 && j == 4 ? 10 :
10826 i == Xboom_2 && j == 5 ? 12 :
10827 i == Xboom_2 && j == 6 ? 12 :
10828 i == Xboom_2 && j == 7 ? 12 :
10829 special_animation && j == 4 ? 3 :
10830 effective_action != action ? 0 :
10834 Bitmap *debug_bitmap = g_em->bitmap;
10835 int debug_src_x = g_em->src_x;
10836 int debug_src_y = g_em->src_y;
10839 int frame = getAnimationFrame(g->anim_frames,
10842 g->anim_start_frame,
10845 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10846 g->double_movement && is_backside);
10848 g_em->bitmap = src_bitmap;
10849 g_em->src_x = src_x;
10850 g_em->src_y = src_y;
10851 g_em->src_offset_x = 0;
10852 g_em->src_offset_y = 0;
10853 g_em->dst_offset_x = 0;
10854 g_em->dst_offset_y = 0;
10855 g_em->width = TILEX;
10856 g_em->height = TILEY;
10858 g_em->preserve_background = FALSE;
10861 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10866 g_em->crumbled_bitmap = NULL;
10867 g_em->crumbled_src_x = 0;
10868 g_em->crumbled_src_y = 0;
10869 g_em->crumbled_border_size = 0;
10871 g_em->has_crumbled_graphics = FALSE;
10874 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10875 printf("::: empty crumbled: %d [%s], %d, %d\n",
10876 effective_element, element_info[effective_element].token_name,
10877 effective_action, direction);
10880 /* if element can be crumbled, but certain action graphics are just empty
10881 space (like instantly snapping sand to empty space in 1 frame), do not
10882 treat these empty space graphics as crumbled graphics in EMC engine */
10883 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10885 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10886 g_crumbled->anim_delay,
10887 g_crumbled->anim_mode,
10888 g_crumbled->anim_start_frame,
10891 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10893 g_em->has_crumbled_graphics = TRUE;
10894 g_em->crumbled_bitmap = src_bitmap;
10895 g_em->crumbled_src_x = src_x;
10896 g_em->crumbled_src_y = src_y;
10897 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10901 if (g_em == &graphic_info_em_object[207][0])
10902 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10903 graphic_info_em_object[207][0].crumbled_src_x,
10904 graphic_info_em_object[207][0].crumbled_src_y,
10906 crumbled, frame, src_x, src_y,
10911 g->anim_start_frame,
10913 gfx.anim_random_frame,
10918 printf("::: EMC tile %d is crumbled\n", i);
10924 if (element == EL_ROCK &&
10925 effective_action == ACTION_FILLING)
10926 printf("::: has_action_graphics == %d\n", has_action_graphics);
10929 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10930 effective_action == ACTION_MOVING ||
10931 effective_action == ACTION_PUSHING ||
10932 effective_action == ACTION_EATING)) ||
10933 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10934 effective_action == ACTION_EMPTYING)))
10937 (effective_action == ACTION_FALLING ||
10938 effective_action == ACTION_FILLING ||
10939 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10940 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10941 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10942 int num_steps = (i == Ydrip_s1 ? 16 :
10943 i == Ydrip_s1B ? 16 :
10944 i == Ydrip_s2 ? 16 :
10945 i == Ydrip_s2B ? 16 :
10946 i == Xsand_stonein_1 ? 32 :
10947 i == Xsand_stonein_2 ? 32 :
10948 i == Xsand_stonein_3 ? 32 :
10949 i == Xsand_stonein_4 ? 32 :
10950 i == Xsand_stoneout_1 ? 16 :
10951 i == Xsand_stoneout_2 ? 16 : 8);
10952 int cx = ABS(dx) * (TILEX / num_steps);
10953 int cy = ABS(dy) * (TILEY / num_steps);
10954 int step_frame = (i == Ydrip_s2 ? j + 8 :
10955 i == Ydrip_s2B ? j + 8 :
10956 i == Xsand_stonein_2 ? j + 8 :
10957 i == Xsand_stonein_3 ? j + 16 :
10958 i == Xsand_stonein_4 ? j + 24 :
10959 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10960 int step = (is_backside ? step_frame : num_steps - step_frame);
10962 if (is_backside) /* tile where movement starts */
10964 if (dx < 0 || dy < 0)
10966 g_em->src_offset_x = cx * step;
10967 g_em->src_offset_y = cy * step;
10971 g_em->dst_offset_x = cx * step;
10972 g_em->dst_offset_y = cy * step;
10975 else /* tile where movement ends */
10977 if (dx < 0 || dy < 0)
10979 g_em->dst_offset_x = cx * step;
10980 g_em->dst_offset_y = cy * step;
10984 g_em->src_offset_x = cx * step;
10985 g_em->src_offset_y = cy * step;
10989 g_em->width = TILEX - cx * step;
10990 g_em->height = TILEY - cy * step;
10993 /* create unique graphic identifier to decide if tile must be redrawn */
10994 /* bit 31 - 16 (16 bit): EM style graphic
10995 bit 15 - 12 ( 4 bit): EM style frame
10996 bit 11 - 6 ( 6 bit): graphic width
10997 bit 5 - 0 ( 6 bit): graphic height */
10998 g_em->unique_identifier =
10999 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11003 /* skip check for EMC elements not contained in original EMC artwork */
11004 if (element == EL_EMC_FAKE_ACID)
11007 if (g_em->bitmap != debug_bitmap ||
11008 g_em->src_x != debug_src_x ||
11009 g_em->src_y != debug_src_y ||
11010 g_em->src_offset_x != 0 ||
11011 g_em->src_offset_y != 0 ||
11012 g_em->dst_offset_x != 0 ||
11013 g_em->dst_offset_y != 0 ||
11014 g_em->width != TILEX ||
11015 g_em->height != TILEY)
11017 static int last_i = -1;
11025 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11026 i, element, element_info[element].token_name,
11027 element_action_info[effective_action].suffix, direction);
11029 if (element != effective_element)
11030 printf(" [%d ('%s')]",
11032 element_info[effective_element].token_name);
11036 if (g_em->bitmap != debug_bitmap)
11037 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11038 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11040 if (g_em->src_x != debug_src_x ||
11041 g_em->src_y != debug_src_y)
11042 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11043 j, (is_backside ? 'B' : 'F'),
11044 g_em->src_x, g_em->src_y,
11045 g_em->src_x / 32, g_em->src_y / 32,
11046 debug_src_x, debug_src_y,
11047 debug_src_x / 32, debug_src_y / 32);
11049 if (g_em->src_offset_x != 0 ||
11050 g_em->src_offset_y != 0 ||
11051 g_em->dst_offset_x != 0 ||
11052 g_em->dst_offset_y != 0)
11053 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11055 g_em->src_offset_x, g_em->src_offset_y,
11056 g_em->dst_offset_x, g_em->dst_offset_y);
11058 if (g_em->width != TILEX ||
11059 g_em->height != TILEY)
11060 printf(" %d (%d): size %d,%d should be %d,%d\n",
11062 g_em->width, g_em->height, TILEX, TILEY);
11064 num_em_gfx_errors++;
11071 for (i = 0; i < TILE_MAX; i++)
11073 for (j = 0; j < 8; j++)
11075 int element = object_mapping[i].element_rnd;
11076 int action = object_mapping[i].action;
11077 int direction = object_mapping[i].direction;
11078 boolean is_backside = object_mapping[i].is_backside;
11079 int graphic_action = el_act_dir2img(element, action, direction);
11080 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11082 if ((action == ACTION_SMASHED_BY_ROCK ||
11083 action == ACTION_SMASHED_BY_SPRING ||
11084 action == ACTION_EATING) &&
11085 graphic_action == graphic_default)
11087 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11088 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11089 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11090 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11093 /* no separate animation for "smashed by rock" -- use rock instead */
11094 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11095 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11097 g_em->bitmap = g_xx->bitmap;
11098 g_em->src_x = g_xx->src_x;
11099 g_em->src_y = g_xx->src_y;
11100 g_em->src_offset_x = g_xx->src_offset_x;
11101 g_em->src_offset_y = g_xx->src_offset_y;
11102 g_em->dst_offset_x = g_xx->dst_offset_x;
11103 g_em->dst_offset_y = g_xx->dst_offset_y;
11104 g_em->width = g_xx->width;
11105 g_em->height = g_xx->height;
11106 g_em->unique_identifier = g_xx->unique_identifier;
11109 g_em->preserve_background = TRUE;
11114 for (p = 0; p < MAX_PLAYERS; p++)
11116 for (i = 0; i < SPR_MAX; i++)
11118 int element = player_mapping[p][i].element_rnd;
11119 int action = player_mapping[p][i].action;
11120 int direction = player_mapping[p][i].direction;
11122 for (j = 0; j < 8; j++)
11124 int effective_element = element;
11125 int effective_action = action;
11126 int graphic = (direction == MV_NONE ?
11127 el_act2img(effective_element, effective_action) :
11128 el_act_dir2img(effective_element, effective_action,
11130 struct GraphicInfo *g = &graphic_info[graphic];
11131 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11132 Bitmap *src_bitmap;
11134 int sync_frame = j;
11137 Bitmap *debug_bitmap = g_em->bitmap;
11138 int debug_src_x = g_em->src_x;
11139 int debug_src_y = g_em->src_y;
11142 int frame = getAnimationFrame(g->anim_frames,
11145 g->anim_start_frame,
11148 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11150 g_em->bitmap = src_bitmap;
11151 g_em->src_x = src_x;
11152 g_em->src_y = src_y;
11153 g_em->src_offset_x = 0;
11154 g_em->src_offset_y = 0;
11155 g_em->dst_offset_x = 0;
11156 g_em->dst_offset_y = 0;
11157 g_em->width = TILEX;
11158 g_em->height = TILEY;
11162 /* skip check for EMC elements not contained in original EMC artwork */
11163 if (element == EL_PLAYER_3 ||
11164 element == EL_PLAYER_4)
11167 if (g_em->bitmap != debug_bitmap ||
11168 g_em->src_x != debug_src_x ||
11169 g_em->src_y != debug_src_y)
11171 static int last_i = -1;
11179 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11180 p, i, element, element_info[element].token_name,
11181 element_action_info[effective_action].suffix, direction);
11183 if (element != effective_element)
11184 printf(" [%d ('%s')]",
11186 element_info[effective_element].token_name);
11190 if (g_em->bitmap != debug_bitmap)
11191 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11192 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11194 if (g_em->src_x != debug_src_x ||
11195 g_em->src_y != debug_src_y)
11196 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11198 g_em->src_x, g_em->src_y,
11199 g_em->src_x / 32, g_em->src_y / 32,
11200 debug_src_x, debug_src_y,
11201 debug_src_x / 32, debug_src_y / 32);
11203 num_em_gfx_errors++;
11213 printf("::: [%d errors found]\n", num_em_gfx_errors);
11219 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11220 boolean any_player_moving,
11221 boolean player_is_dropping)
11223 if (tape.single_step && tape.recording && !tape.pausing)
11226 boolean active_players = FALSE;
11229 for (i = 0; i < MAX_PLAYERS; i++)
11230 if (action[i] != JOY_NO_ACTION)
11231 active_players = TRUE;
11235 if (frame == 0 && !player_is_dropping)
11236 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11240 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11241 boolean murphy_is_dropping)
11244 printf("::: waiting: %d, dropping: %d\n",
11245 murphy_is_waiting, murphy_is_dropping);
11248 if (tape.single_step && tape.recording && !tape.pausing)
11250 // if (murphy_is_waiting || murphy_is_dropping)
11251 if (murphy_is_waiting)
11254 printf("::: murphy is waiting -> pause mode\n");
11257 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11262 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11263 int graphic, int sync_frame, int x, int y)
11265 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11267 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11270 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11272 return (IS_NEXT_FRAME(sync_frame, graphic));
11275 int getGraphicInfo_Delay(int graphic)
11277 return graphic_info[graphic].anim_delay;
11280 void PlayMenuSoundExt(int sound)
11282 if (sound == SND_UNDEFINED)
11285 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11286 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11289 if (IS_LOOP_SOUND(sound))
11290 PlaySoundLoop(sound);
11295 void PlayMenuSound()
11297 PlayMenuSoundExt(menu.sound[game_status]);
11300 void PlayMenuSoundStereo(int sound, int stereo_position)
11302 if (sound == SND_UNDEFINED)
11305 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11306 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11309 if (IS_LOOP_SOUND(sound))
11310 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11312 PlaySoundStereo(sound, stereo_position);
11315 void PlayMenuSoundIfLoopExt(int sound)
11317 if (sound == SND_UNDEFINED)
11320 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11321 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11324 if (IS_LOOP_SOUND(sound))
11325 PlaySoundLoop(sound);
11328 void PlayMenuSoundIfLoop()
11330 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11333 void PlayMenuMusicExt(int music)
11335 if (music == MUS_UNDEFINED)
11338 if (!setup.sound_music)
11344 void PlayMenuMusic()
11346 PlayMenuMusicExt(menu.music[game_status]);
11349 void PlaySoundActivating()
11352 PlaySound(SND_MENU_ITEM_ACTIVATING);
11356 void PlaySoundSelecting()
11359 PlaySound(SND_MENU_ITEM_SELECTING);
11363 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11365 boolean change_fullscreen = (setup.fullscreen !=
11366 video.fullscreen_enabled);
11367 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11368 !strEqual(setup.fullscreen_mode,
11369 video.fullscreen_mode_current));
11370 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11371 setup.window_scaling_percent !=
11372 video.window_scaling_percent);
11374 if (change_window_scaling_percent && video.fullscreen_enabled)
11377 if (!change_window_scaling_percent && !video.fullscreen_available)
11380 #if defined(TARGET_SDL2)
11381 if (change_window_scaling_percent)
11383 SDLSetWindowScaling(setup.window_scaling_percent);
11387 else if (change_fullscreen)
11389 SDLSetWindowFullscreen(setup.fullscreen);
11391 /* set setup value according to successfully changed fullscreen mode */
11392 setup.fullscreen = video.fullscreen_enabled;
11398 if (change_fullscreen ||
11399 change_fullscreen_mode ||
11400 change_window_scaling_percent)
11402 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11404 /* save backbuffer content which gets lost when toggling fullscreen mode */
11405 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11407 if (change_fullscreen_mode)
11409 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11410 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11413 if (change_window_scaling_percent)
11415 /* keep window mode, but change window scaling */
11416 video.fullscreen_enabled = TRUE; /* force new window scaling */
11419 /* toggle fullscreen */
11420 ChangeVideoModeIfNeeded(setup.fullscreen);
11422 /* set setup value according to successfully changed fullscreen mode */
11423 setup.fullscreen = video.fullscreen_enabled;
11425 /* restore backbuffer content from temporary backbuffer backup bitmap */
11426 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11428 FreeBitmap(tmp_backbuffer);
11431 /* update visible window/screen */
11432 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11434 redraw_mask = REDRAW_ALL;
11439 void ChangeViewportPropertiesIfNeeded()
11442 int *door_1_x = &DX;
11443 int *door_1_y = &DY;
11444 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11445 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11448 int gfx_game_mode = game_status;
11450 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11451 game_status == GAME_MODE_EDITOR ? game_status :
11454 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11456 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11457 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11458 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11459 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11460 int border_size = vp_playfield->border_size;
11461 int new_sx = vp_playfield->x + border_size;
11462 int new_sy = vp_playfield->y + border_size;
11463 int new_sxsize = vp_playfield->width - 2 * border_size;
11464 int new_sysize = vp_playfield->height - 2 * border_size;
11465 int new_real_sx = vp_playfield->x;
11466 int new_real_sy = vp_playfield->y;
11467 int new_full_sxsize = vp_playfield->width;
11468 int new_full_sysize = vp_playfield->height;
11469 int new_dx = vp_door_1->x;
11470 int new_dy = vp_door_1->y;
11471 int new_dxsize = vp_door_1->width;
11472 int new_dysize = vp_door_1->height;
11473 int new_vx = vp_door_2->x;
11474 int new_vy = vp_door_2->y;
11475 int new_vxsize = vp_door_2->width;
11476 int new_vysize = vp_door_2->height;
11477 int new_ex = vp_door_3->x;
11478 int new_ey = vp_door_3->y;
11479 int new_exsize = vp_door_3->width;
11480 int new_eysize = vp_door_3->height;
11482 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11483 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11484 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11485 int new_scr_fieldx = new_sxsize / tilesize;
11486 int new_scr_fieldy = new_sysize / tilesize;
11487 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11488 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11490 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11491 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11493 boolean init_gfx_buffers = FALSE;
11494 boolean init_video_buffer = FALSE;
11495 boolean init_gadgets_and_toons = FALSE;
11498 /* !!! TEST ONLY !!! */
11499 // InitGfxBuffers();
11503 if (viewport.window.width != WIN_XSIZE ||
11504 viewport.window.height != WIN_YSIZE)
11506 WIN_XSIZE = viewport.window.width;
11507 WIN_YSIZE = viewport.window.height;
11510 init_video_buffer = TRUE;
11511 init_gfx_buffers = TRUE;
11513 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11517 SetDrawDeactivationMask(REDRAW_NONE);
11518 SetDrawBackgroundMask(REDRAW_FIELD);
11520 // RedrawBackground();
11524 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11527 if (new_scr_fieldx != SCR_FIELDX ||
11528 new_scr_fieldy != SCR_FIELDY)
11530 /* this always toggles between MAIN and GAME when using small tile size */
11532 SCR_FIELDX = new_scr_fieldx;
11533 SCR_FIELDY = new_scr_fieldy;
11535 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11539 if (new_tilesize_var != TILESIZE_VAR &&
11540 gfx_game_mode == GAME_MODE_PLAYING)
11542 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11544 TILESIZE_VAR = new_tilesize_var;
11546 init_gfx_buffers = TRUE;
11548 // printf("::: tilesize: init_gfx_buffers\n");
11552 if (new_sx != SX ||
11560 new_sxsize != SXSIZE ||
11561 new_sysize != SYSIZE ||
11562 new_dxsize != DXSIZE ||
11563 new_dysize != DYSIZE ||
11564 new_vxsize != VXSIZE ||
11565 new_vysize != VYSIZE ||
11566 new_exsize != EXSIZE ||
11567 new_eysize != EYSIZE ||
11568 new_real_sx != REAL_SX ||
11569 new_real_sy != REAL_SY ||
11570 new_full_sxsize != FULL_SXSIZE ||
11571 new_full_sysize != FULL_SYSIZE ||
11572 new_tilesize_var != TILESIZE_VAR
11575 vp_door_1->x != *door_1_x ||
11576 vp_door_1->y != *door_1_y ||
11577 vp_door_2->x != *door_2_x ||
11578 vp_door_2->y != *door_2_y
11583 // changing tile size invalidates scroll values of engine snapshots
11584 if (new_tilesize_var != TILESIZE_VAR)
11586 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11588 FreeEngineSnapshot();
11600 SXSIZE = new_sxsize;
11601 SYSIZE = new_sysize;
11602 DXSIZE = new_dxsize;
11603 DYSIZE = new_dysize;
11604 VXSIZE = new_vxsize;
11605 VYSIZE = new_vysize;
11606 EXSIZE = new_exsize;
11607 EYSIZE = new_eysize;
11608 REAL_SX = new_real_sx;
11609 REAL_SY = new_real_sy;
11610 FULL_SXSIZE = new_full_sxsize;
11611 FULL_SYSIZE = new_full_sysize;
11612 TILESIZE_VAR = new_tilesize_var;
11615 printf("::: %d, %d, %d [%d]\n",
11616 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11617 setup.small_game_graphics);
11621 *door_1_x = vp_door_1->x;
11622 *door_1_y = vp_door_1->y;
11623 *door_2_x = vp_door_2->x;
11624 *door_2_y = vp_door_2->y;
11628 init_gfx_buffers = TRUE;
11630 // printf("::: viewports: init_gfx_buffers\n");
11636 if (gfx_game_mode == GAME_MODE_MAIN)
11640 init_gadgets_and_toons = TRUE;
11642 // printf("::: viewports: init_gadgets_and_toons\n");
11650 if (init_gfx_buffers)
11652 // printf("::: init_gfx_buffers\n");
11654 SCR_FIELDX = new_scr_fieldx_buffers;
11655 SCR_FIELDY = new_scr_fieldy_buffers;
11659 SCR_FIELDX = new_scr_fieldx;
11660 SCR_FIELDY = new_scr_fieldy;
11663 if (init_video_buffer)
11665 // printf("::: init_video_buffer\n");
11667 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11669 SetDrawDeactivationMask(REDRAW_NONE);
11670 SetDrawBackgroundMask(REDRAW_FIELD);
11673 if (init_gadgets_and_toons)
11675 // printf("::: init_gadgets_and_toons\n");
11682 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);