1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_GFX_DOOR_1_PART_1,
74 IMG_GFX_DOOR_1_PART_2,
79 IMG_GFX_DOOR_1_PART_3,
84 IMG_GFX_DOOR_1_PART_4,
89 IMG_GFX_DOOR_1_PART_5,
94 IMG_GFX_DOOR_1_PART_6,
99 IMG_GFX_DOOR_1_PART_7,
104 IMG_GFX_DOOR_1_PART_8,
110 IMG_GFX_DOOR_2_PART_1,
115 IMG_GFX_DOOR_2_PART_2,
120 IMG_GFX_DOOR_2_PART_3,
125 IMG_GFX_DOOR_2_PART_4,
130 IMG_GFX_DOOR_2_PART_5,
135 IMG_GFX_DOOR_2_PART_6,
140 IMG_GFX_DOOR_2_PART_7,
145 IMG_GFX_DOOR_2_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons(void);
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static char *print_if_not_empty(int element)
179 static char *s = NULL;
180 char *token_name = element_info[element].token_name;
185 s = checked_malloc(strlen(token_name) + 10 + 1);
187 if (element != EL_EMPTY)
188 sprintf(s, "%d\t['%s']", element, token_name);
190 sprintf(s, "%d", element);
195 int correctLevelPosX_EM(int lx)
198 lx -= (BorderElement != EL_EMPTY ? 1 : 0);
203 int correctLevelPosY_EM(int ly)
206 ly -= (BorderElement != EL_EMPTY ? 1 : 0);
211 static int getFieldbufferOffsetX_RND(void)
213 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
214 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
215 int dx_var = dx * TILESIZE_VAR / TILESIZE;
218 if (EVEN(SCR_FIELDX))
220 int ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
222 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
223 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
225 fx += (dx_var > 0 ? TILEX_VAR : 0);
232 if (full_lev_fieldx <= SCR_FIELDX)
234 if (EVEN(SCR_FIELDX))
235 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
237 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
243 static int getFieldbufferOffsetY_RND(void)
245 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
246 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
247 int dy_var = dy * TILESIZE_VAR / TILESIZE;
250 if (EVEN(SCR_FIELDY))
252 int ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
254 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
255 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
257 fy += (dy_var > 0 ? TILEY_VAR : 0);
264 if (full_lev_fieldy <= SCR_FIELDY)
266 if (EVEN(SCR_FIELDY))
267 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
269 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
275 static int getLevelFromScreenX_RND(int sx)
277 int fx = getFieldbufferOffsetX_RND();
280 int lx = LEVELX((px + dx) / TILESIZE_VAR);
285 static int getLevelFromScreenY_RND(int sy)
287 int fy = getFieldbufferOffsetY_RND();
290 int ly = LEVELY((py + dy) / TILESIZE_VAR);
295 static int getLevelFromScreenX_EM(int sx)
297 int level_xsize = level.native_em_level->lev->width;
298 int full_xsize = level_xsize * TILESIZE_VAR;
300 sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
302 int fx = getFieldbufferOffsetX_EM();
305 int lx = LEVELX((px + dx) / TILESIZE_VAR);
307 lx = correctLevelPosX_EM(lx);
312 static int getLevelFromScreenY_EM(int sy)
314 int level_ysize = level.native_em_level->lev->height;
315 int full_ysize = level_ysize * TILESIZE_VAR;
317 sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
319 int fy = getFieldbufferOffsetY_EM();
322 int ly = LEVELY((py + dy) / TILESIZE_VAR);
324 ly = correctLevelPosY_EM(ly);
329 static int getLevelFromScreenX_SP(int sx)
331 int menBorder = setup.sp_show_border_elements;
332 int level_xsize = level.native_sp_level->width;
333 int full_xsize = (level_xsize - (menBorder ? 0 : 1)) * TILESIZE_VAR;
335 sx += (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
337 int fx = getFieldbufferOffsetX_SP();
340 int lx = LEVELX((px + dx) / TILESIZE_VAR);
345 static int getLevelFromScreenY_SP(int sy)
347 int menBorder = setup.sp_show_border_elements;
348 int level_ysize = level.native_sp_level->height;
349 int full_ysize = (level_ysize - (menBorder ? 0 : 1)) * TILESIZE_VAR;
351 sy += (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
353 int fy = getFieldbufferOffsetY_SP();
356 int ly = LEVELY((py + dy) / TILESIZE_VAR);
361 static int getLevelFromScreenX_MM(int sx)
363 int level_xsize = level.native_mm_level->fieldx;
364 int full_xsize = level_xsize * TILESIZE_VAR;
366 sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
369 int lx = (px + TILESIZE_VAR) / TILESIZE_VAR - 1;
374 static int getLevelFromScreenY_MM(int sy)
376 int level_ysize = level.native_mm_level->fieldy;
377 int full_ysize = level_ysize * TILESIZE_VAR;
379 sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
382 int ly = (py + TILESIZE_VAR) / TILESIZE_VAR - 1;
387 int getLevelFromScreenX(int x)
389 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
390 return getLevelFromScreenX_EM(x);
391 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
392 return getLevelFromScreenX_SP(x);
393 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
394 return getLevelFromScreenX_MM(x);
396 return getLevelFromScreenX_RND(x);
399 int getLevelFromScreenY(int y)
401 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
402 return getLevelFromScreenY_EM(y);
403 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
404 return getLevelFromScreenY_SP(y);
405 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
406 return getLevelFromScreenY_MM(y);
408 return getLevelFromScreenY_RND(y);
411 void DumpTile(int x, int y)
417 printf_line("-", 79);
418 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
419 printf_line("-", 79);
421 if (!IN_LEV_FIELD(x, y))
423 printf("(not in level field)\n");
429 token_name = element_info[Feld[x][y]].token_name;
431 printf(" Feld: %d\t['%s']\n", Feld[x][y], token_name);
432 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
433 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
434 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
435 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
436 printf(" MovPos: %d\n", MovPos[x][y]);
437 printf(" MovDir: %d\n", MovDir[x][y]);
438 printf(" MovDelay: %d\n", MovDelay[x][y]);
439 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
440 printf(" CustomValue: %d\n", CustomValue[x][y]);
441 printf(" GfxElement: %d\n", GfxElement[x][y]);
442 printf(" GfxAction: %d\n", GfxAction[x][y]);
443 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
444 printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy);
448 void DumpTileFromScreen(int sx, int sy)
450 int lx = getLevelFromScreenX(sx);
451 int ly = getLevelFromScreenY(sy);
456 void SetDrawtoField(int mode)
458 if (mode == DRAW_TO_FIELDBUFFER)
464 BX2 = SCR_FIELDX + 1;
465 BY2 = SCR_FIELDY + 1;
467 drawto_field = fieldbuffer;
469 else /* DRAW_TO_BACKBUFFER */
475 BX2 = SCR_FIELDX - 1;
476 BY2 = SCR_FIELDY - 1;
478 drawto_field = backbuffer;
482 static void RedrawPlayfield_RND(void)
484 if (game.envelope_active)
487 DrawLevel(REDRAW_ALL);
491 void RedrawPlayfield(void)
493 if (game_status != GAME_MODE_PLAYING)
496 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
497 RedrawPlayfield_EM(TRUE);
498 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
499 RedrawPlayfield_SP(TRUE);
500 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
501 RedrawPlayfield_MM();
502 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
503 RedrawPlayfield_RND();
505 BlitScreenToBitmap(backbuffer);
507 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
511 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
514 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
515 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
517 if (x == -1 && y == -1)
520 if (draw_target == DRAW_TO_SCREEN)
521 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
523 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
526 static void DrawMaskedBorderExt_FIELD(int draw_target)
528 if (global.border_status >= GAME_MODE_MAIN &&
529 global.border_status <= GAME_MODE_PLAYING &&
530 border.draw_masked[global.border_status])
531 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
535 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
537 // when drawing to backbuffer, never draw border over open doors
538 if (draw_target == DRAW_TO_BACKBUFFER &&
539 (GetDoorState() & DOOR_OPEN_1))
542 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
543 (global.border_status != GAME_MODE_EDITOR ||
544 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
545 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
548 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
550 // when drawing to backbuffer, never draw border over open doors
551 if (draw_target == DRAW_TO_BACKBUFFER &&
552 (GetDoorState() & DOOR_OPEN_2))
555 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
556 global.border_status != GAME_MODE_EDITOR)
557 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
560 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
562 /* currently not available */
565 static void DrawMaskedBorderExt_ALL(int draw_target)
567 DrawMaskedBorderExt_FIELD(draw_target);
568 DrawMaskedBorderExt_DOOR_1(draw_target);
569 DrawMaskedBorderExt_DOOR_2(draw_target);
570 DrawMaskedBorderExt_DOOR_3(draw_target);
573 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
575 /* never draw masked screen borders on borderless screens */
576 if (global.border_status == GAME_MODE_LOADING ||
577 global.border_status == GAME_MODE_TITLE)
580 if (redraw_mask & REDRAW_ALL)
581 DrawMaskedBorderExt_ALL(draw_target);
584 if (redraw_mask & REDRAW_FIELD)
585 DrawMaskedBorderExt_FIELD(draw_target);
586 if (redraw_mask & REDRAW_DOOR_1)
587 DrawMaskedBorderExt_DOOR_1(draw_target);
588 if (redraw_mask & REDRAW_DOOR_2)
589 DrawMaskedBorderExt_DOOR_2(draw_target);
590 if (redraw_mask & REDRAW_DOOR_3)
591 DrawMaskedBorderExt_DOOR_3(draw_target);
595 void DrawMaskedBorder_FIELD(void)
597 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
600 void DrawMaskedBorder(int redraw_mask)
602 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
605 void DrawMaskedBorderToTarget(int draw_target)
607 if (draw_target == DRAW_TO_BACKBUFFER ||
608 draw_target == DRAW_TO_SCREEN)
610 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
614 int last_border_status = global.border_status;
616 if (draw_target == DRAW_TO_FADE_SOURCE)
618 global.border_status = gfx.fade_border_source_status;
619 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
621 else if (draw_target == DRAW_TO_FADE_TARGET)
623 global.border_status = gfx.fade_border_target_status;
624 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
627 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
629 global.border_status = last_border_status;
630 gfx.masked_border_bitmap_ptr = backbuffer;
634 void DrawTileCursor(int draw_target)
640 int graphic = IMG_GLOBAL_TILE_CURSOR;
642 int tilesize = TILESIZE_VAR;
643 int width = tilesize;
644 int height = tilesize;
646 if (game_status != GAME_MODE_PLAYING)
649 if (!tile_cursor.enabled ||
653 if (tile_cursor.moving)
655 int step = TILESIZE_VAR / 4;
656 int dx = tile_cursor.target_x - tile_cursor.x;
657 int dy = tile_cursor.target_y - tile_cursor.y;
660 tile_cursor.x = tile_cursor.target_x;
662 tile_cursor.x += SIGN(dx) * step;
665 tile_cursor.y = tile_cursor.target_y;
667 tile_cursor.y += SIGN(dy) * step;
669 if (tile_cursor.x == tile_cursor.target_x &&
670 tile_cursor.y == tile_cursor.target_y)
671 tile_cursor.moving = FALSE;
674 dst_x = tile_cursor.x;
675 dst_y = tile_cursor.y;
677 frame = getGraphicAnimationFrame(graphic, -1);
679 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
682 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
683 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
685 if (draw_target == DRAW_TO_SCREEN)
686 BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y);
688 BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
692 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
694 int fx = getFieldbufferOffsetX_RND();
695 int fy = getFieldbufferOffsetY_RND();
697 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
700 void BlitScreenToBitmap(Bitmap *target_bitmap)
702 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
703 BlitScreenToBitmap_EM(target_bitmap);
704 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
705 BlitScreenToBitmap_SP(target_bitmap);
706 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
707 BlitScreenToBitmap_MM(target_bitmap);
708 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
709 BlitScreenToBitmap_RND(target_bitmap);
711 redraw_mask |= REDRAW_FIELD;
714 static void DrawFramesPerSecond(void)
717 int font_nr = FONT_TEXT_2;
718 int font_width = getFontWidth(font_nr);
719 int draw_deactivation_mask = GetDrawDeactivationMask();
720 boolean draw_masked = (draw_deactivation_mask == REDRAW_NONE);
722 /* draw FPS with leading space (needed if field buffer deactivated) */
723 sprintf(text, " %04.1f fps", global.frames_per_second);
725 /* override draw deactivation mask (required for invisible warp mode) */
726 SetDrawDeactivationMask(REDRAW_NONE);
728 /* draw opaque FPS if field buffer deactivated, else draw masked FPS */
729 DrawTextExt(backbuffer, SX + SXSIZE - font_width * strlen(text), SY, text,
730 font_nr, (draw_masked ? BLIT_MASKED : BLIT_OPAQUE));
732 /* set draw deactivation mask to previous value */
733 SetDrawDeactivationMask(draw_deactivation_mask);
735 /* force full-screen redraw in this frame */
736 redraw_mask = REDRAW_ALL;
740 static void PrintFrameTimeDebugging(void)
742 static unsigned int last_counter = 0;
743 unsigned int counter = Counter();
744 int diff_1 = counter - last_counter;
745 int diff_2 = diff_1 - GAME_FRAME_DELAY;
747 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
748 char diff_bar[2 * diff_2_max + 5];
752 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
754 for (i = 0; i < diff_2_max; i++)
755 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
756 i >= diff_2_max - diff_2_cut ? '-' : ' ');
758 diff_bar[pos++] = '|';
760 for (i = 0; i < diff_2_max; i++)
761 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
763 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
765 diff_bar[pos++] = '\0';
767 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
770 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
773 last_counter = counter;
777 static int unifiedRedrawMask(int mask)
779 if (mask & REDRAW_ALL)
782 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
788 static boolean equalRedrawMasks(int mask_1, int mask_2)
790 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
793 void BackToFront(void)
795 static int last_redraw_mask = REDRAW_NONE;
797 // force screen redraw in every frame to continue drawing global animations
798 // (but always use the last redraw mask to prevent unwanted side effects)
799 if (redraw_mask == REDRAW_NONE)
800 redraw_mask = last_redraw_mask;
802 last_redraw_mask = redraw_mask;
805 // masked border now drawn immediately when blitting backbuffer to window
807 // draw masked border to all viewports, if defined
808 DrawMaskedBorder(redraw_mask);
811 // draw frames per second (only if debug mode is enabled)
812 if (redraw_mask & REDRAW_FPS)
813 DrawFramesPerSecond();
815 // remove playfield redraw before potentially merging with doors redraw
816 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
817 redraw_mask &= ~REDRAW_FIELD;
819 // redraw complete window if both playfield and (some) doors need redraw
820 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
821 redraw_mask = REDRAW_ALL;
823 /* although redrawing the whole window would be fine for normal gameplay,
824 being able to only redraw the playfield is required for deactivating
825 certain drawing areas (mainly playfield) to work, which is needed for
826 warp-forward to be fast enough (by skipping redraw of most frames) */
828 if (redraw_mask & REDRAW_ALL)
830 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
832 else if (redraw_mask & REDRAW_FIELD)
834 BlitBitmap(backbuffer, window,
835 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
837 else if (redraw_mask & REDRAW_DOORS)
839 // merge door areas to prevent calling screen redraw more than once
845 if (redraw_mask & REDRAW_DOOR_1)
849 x2 = MAX(x2, DX + DXSIZE);
850 y2 = MAX(y2, DY + DYSIZE);
853 if (redraw_mask & REDRAW_DOOR_2)
857 x2 = MAX(x2, VX + VXSIZE);
858 y2 = MAX(y2, VY + VYSIZE);
861 if (redraw_mask & REDRAW_DOOR_3)
865 x2 = MAX(x2, EX + EXSIZE);
866 y2 = MAX(y2, EY + EYSIZE);
869 // make sure that at least one pixel is blitted, and inside the screen
870 // (else nothing is blitted, causing the animations not to be updated)
871 x1 = MIN(MAX(0, x1), WIN_XSIZE - 1);
872 y1 = MIN(MAX(0, y1), WIN_YSIZE - 1);
873 x2 = MIN(MAX(1, x2), WIN_XSIZE);
874 y2 = MIN(MAX(1, y2), WIN_YSIZE);
876 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
879 redraw_mask = REDRAW_NONE;
882 PrintFrameTimeDebugging();
886 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
888 unsigned int frame_delay_value_old = GetVideoFrameDelay();
890 SetVideoFrameDelay(frame_delay_value);
894 SetVideoFrameDelay(frame_delay_value_old);
897 static int fade_type_skip = FADE_TYPE_NONE;
899 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
901 void (*draw_border_function)(void) = NULL;
902 int x, y, width, height;
903 int fade_delay, post_delay;
905 if (fade_type == FADE_TYPE_FADE_OUT)
907 if (fade_type_skip != FADE_TYPE_NONE)
909 /* skip all fade operations until specified fade operation */
910 if (fade_type & fade_type_skip)
911 fade_type_skip = FADE_TYPE_NONE;
916 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
920 redraw_mask |= fade_mask;
922 if (fade_type == FADE_TYPE_SKIP)
924 fade_type_skip = fade_mode;
929 fade_delay = fading.fade_delay;
930 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
932 if (fade_type_skip != FADE_TYPE_NONE)
934 /* skip all fade operations until specified fade operation */
935 if (fade_type & fade_type_skip)
936 fade_type_skip = FADE_TYPE_NONE;
941 if (global.autoplay_leveldir)
946 if (fade_mask == REDRAW_FIELD)
951 height = FADE_SYSIZE;
953 if (border.draw_masked_when_fading)
954 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
956 DrawMaskedBorder_FIELD(); /* draw once */
958 else /* REDRAW_ALL */
966 if (!setup.fade_screens ||
968 fading.fade_mode == FADE_MODE_NONE)
970 if (fade_mode == FADE_MODE_FADE_OUT)
973 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
975 redraw_mask &= ~fade_mask;
980 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
981 draw_border_function);
983 redraw_mask &= ~fade_mask;
985 ClearAutoRepeatKeyEvents();
988 static void SetScreenStates_BeforeFadingIn(void)
990 // temporarily set screen mode for animations to screen after fading in
991 global.anim_status = global.anim_status_next;
993 // store backbuffer with all animations that will be started after fading in
994 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
995 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
997 // set screen mode for animations back to fading
998 global.anim_status = GAME_MODE_PSEUDO_FADING;
1001 static void SetScreenStates_AfterFadingIn(void)
1003 // store new source screen (to use correct masked border for fading)
1004 gfx.fade_border_source_status = global.border_status;
1006 global.anim_status = global.anim_status_next;
1009 static void SetScreenStates_BeforeFadingOut(void)
1011 // store new target screen (to use correct masked border for fading)
1012 gfx.fade_border_target_status = game_status;
1014 // set screen mode for animations to fading
1015 global.anim_status = GAME_MODE_PSEUDO_FADING;
1017 // store backbuffer with all animations that will be stopped for fading out
1018 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
1019 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
1022 static void SetScreenStates_AfterFadingOut(void)
1024 global.border_status = game_status;
1027 void FadeIn(int fade_mask)
1029 SetScreenStates_BeforeFadingIn();
1032 DrawMaskedBorder(REDRAW_ALL);
1035 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1036 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1038 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1042 FADE_SXSIZE = FULL_SXSIZE;
1043 FADE_SYSIZE = FULL_SYSIZE;
1045 if (game_status == GAME_MODE_PLAYING &&
1046 strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
1047 SetOverlayActive(TRUE);
1049 SetScreenStates_AfterFadingIn();
1051 // force update of global animation status in case of rapid screen changes
1052 redraw_mask = REDRAW_ALL;
1056 void FadeOut(int fade_mask)
1058 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
1059 if (!equalRedrawMasks(fade_mask, redraw_mask))
1062 SetScreenStates_BeforeFadingOut();
1064 SetTileCursorActive(FALSE);
1065 SetOverlayActive(FALSE);
1068 DrawMaskedBorder(REDRAW_ALL);
1071 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1072 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1074 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1076 SetScreenStates_AfterFadingOut();
1079 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1081 static struct TitleFadingInfo fading_leave_stored;
1084 fading_leave_stored = fading_leave;
1086 fading = fading_leave_stored;
1089 void FadeSetEnterMenu(void)
1091 fading = menu.enter_menu;
1093 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1096 void FadeSetLeaveMenu(void)
1098 fading = menu.leave_menu;
1100 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1103 void FadeSetEnterScreen(void)
1105 fading = menu.enter_screen[game_status];
1107 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1110 void FadeSetNextScreen(void)
1112 fading = menu.next_screen[game_status];
1114 // (do not overwrite fade mode set by FadeSetEnterScreen)
1115 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1118 void FadeSetLeaveScreen(void)
1120 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1123 void FadeSetFromType(int type)
1125 if (type & TYPE_ENTER_SCREEN)
1126 FadeSetEnterScreen();
1127 else if (type & TYPE_ENTER)
1129 else if (type & TYPE_LEAVE)
1133 void FadeSetDisabled(void)
1135 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1137 fading = fading_none;
1140 void FadeSkipNextFadeIn(void)
1142 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1145 void FadeSkipNextFadeOut(void)
1147 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1150 static Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1152 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1154 return (graphic == IMG_UNDEFINED ? NULL :
1155 graphic_info[graphic].bitmap != NULL || redefined ?
1156 graphic_info[graphic].bitmap :
1157 graphic_info[default_graphic].bitmap);
1160 static Bitmap *getBackgroundBitmap(int graphic)
1162 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1165 static Bitmap *getGlobalBorderBitmap(int graphic)
1167 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1170 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1173 (status == GAME_MODE_MAIN ||
1174 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1175 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1176 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1177 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1180 return getGlobalBorderBitmap(graphic);
1183 void SetWindowBackgroundImageIfDefined(int graphic)
1185 if (graphic_info[graphic].bitmap)
1186 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1189 void SetMainBackgroundImageIfDefined(int graphic)
1191 if (graphic_info[graphic].bitmap)
1192 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1195 void SetDoorBackgroundImageIfDefined(int graphic)
1197 if (graphic_info[graphic].bitmap)
1198 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1201 void SetWindowBackgroundImage(int graphic)
1203 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1206 void SetMainBackgroundImage(int graphic)
1208 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1211 void SetDoorBackgroundImage(int graphic)
1213 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1216 void SetPanelBackground(void)
1218 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1220 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1221 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1223 SetDoorBackgroundBitmap(bitmap_db_panel);
1226 void DrawBackground(int x, int y, int width, int height)
1228 /* "drawto" might still point to playfield buffer here (hall of fame) */
1229 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1231 if (IN_GFX_FIELD_FULL(x, y))
1232 redraw_mask |= REDRAW_FIELD;
1233 else if (IN_GFX_DOOR_1(x, y))
1234 redraw_mask |= REDRAW_DOOR_1;
1235 else if (IN_GFX_DOOR_2(x, y))
1236 redraw_mask |= REDRAW_DOOR_2;
1237 else if (IN_GFX_DOOR_3(x, y))
1238 redraw_mask |= REDRAW_DOOR_3;
1241 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1243 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1245 if (font->bitmap == NULL)
1248 DrawBackground(x, y, width, height);
1251 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1253 struct GraphicInfo *g = &graphic_info[graphic];
1255 if (g->bitmap == NULL)
1258 DrawBackground(x, y, width, height);
1261 static int game_status_last = -1;
1262 static Bitmap *global_border_bitmap_last = NULL;
1263 static Bitmap *global_border_bitmap = NULL;
1264 static int real_sx_last = -1, real_sy_last = -1;
1265 static int full_sxsize_last = -1, full_sysize_last = -1;
1266 static int dx_last = -1, dy_last = -1;
1267 static int dxsize_last = -1, dysize_last = -1;
1268 static int vx_last = -1, vy_last = -1;
1269 static int vxsize_last = -1, vysize_last = -1;
1270 static int ex_last = -1, ey_last = -1;
1271 static int exsize_last = -1, eysize_last = -1;
1273 boolean CheckIfGlobalBorderHasChanged(void)
1275 // if game status has not changed, global border has not changed either
1276 if (game_status == game_status_last)
1279 // determine and store new global border bitmap for current game status
1280 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1282 return (global_border_bitmap_last != global_border_bitmap);
1285 #define ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED 0
1287 #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
1288 static boolean CheckIfGlobalBorderRedrawIsNeeded(void)
1290 // if game status has not changed, nothing has to be redrawn
1291 if (game_status == game_status_last)
1294 // redraw if last screen was title screen
1295 if (game_status_last == GAME_MODE_TITLE)
1298 // redraw if global screen border has changed
1299 if (CheckIfGlobalBorderHasChanged())
1302 // redraw if position or size of playfield area has changed
1303 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1304 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1307 // redraw if position or size of door area has changed
1308 if (dx_last != DX || dy_last != DY ||
1309 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1312 // redraw if position or size of tape area has changed
1313 if (vx_last != VX || vy_last != VY ||
1314 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1317 // redraw if position or size of editor area has changed
1318 if (ex_last != EX || ey_last != EY ||
1319 exsize_last != EXSIZE || eysize_last != EYSIZE)
1326 static void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1329 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1331 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1334 void RedrawGlobalBorder(void)
1336 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1338 RedrawGlobalBorderFromBitmap(bitmap);
1340 redraw_mask = REDRAW_ALL;
1343 static void RedrawGlobalBorderIfNeeded(void)
1345 #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
1346 if (game_status == game_status_last)
1350 // copy current draw buffer to later copy back areas that have not changed
1351 if (game_status_last != GAME_MODE_TITLE)
1352 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1354 #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
1355 if (CheckIfGlobalBorderRedrawIsNeeded())
1358 // redraw global screen border (or clear, if defined to be empty)
1359 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1361 if (game_status == GAME_MODE_EDITOR)
1362 DrawSpecialEditorDoor();
1364 // copy previous playfield and door areas, if they are defined on both
1365 // previous and current screen and if they still have the same size
1367 if (real_sx_last != -1 && real_sy_last != -1 &&
1368 REAL_SX != -1 && REAL_SY != -1 &&
1369 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1370 BlitBitmap(bitmap_db_store_1, backbuffer,
1371 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1374 if (dx_last != -1 && dy_last != -1 &&
1375 DX != -1 && DY != -1 &&
1376 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1377 BlitBitmap(bitmap_db_store_1, backbuffer,
1378 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1380 if (game_status != GAME_MODE_EDITOR)
1382 if (vx_last != -1 && vy_last != -1 &&
1383 VX != -1 && VY != -1 &&
1384 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1385 BlitBitmap(bitmap_db_store_1, backbuffer,
1386 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1390 if (ex_last != -1 && ey_last != -1 &&
1391 EX != -1 && EY != -1 &&
1392 exsize_last == EXSIZE && eysize_last == EYSIZE)
1393 BlitBitmap(bitmap_db_store_1, backbuffer,
1394 ex_last, ey_last, EXSIZE, EYSIZE, EX, EY);
1397 redraw_mask = REDRAW_ALL;
1400 game_status_last = game_status;
1402 global_border_bitmap_last = global_border_bitmap;
1404 real_sx_last = REAL_SX;
1405 real_sy_last = REAL_SY;
1406 full_sxsize_last = FULL_SXSIZE;
1407 full_sysize_last = FULL_SYSIZE;
1410 dxsize_last = DXSIZE;
1411 dysize_last = DYSIZE;
1414 vxsize_last = VXSIZE;
1415 vysize_last = VYSIZE;
1418 exsize_last = EXSIZE;
1419 eysize_last = EYSIZE;
1422 void ClearField(void)
1424 RedrawGlobalBorderIfNeeded();
1426 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1427 /* (when entering hall of fame after playing) */
1428 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1430 /* !!! maybe this should be done before clearing the background !!! */
1431 if (game_status == GAME_MODE_PLAYING)
1433 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1434 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1438 SetDrawtoField(DRAW_TO_BACKBUFFER);
1442 void MarkTileDirty(int x, int y)
1444 redraw_mask |= REDRAW_FIELD;
1447 void SetBorderElement(void)
1451 BorderElement = EL_EMPTY;
1453 /* the MM game engine does not use a visible border element */
1454 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
1457 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1459 for (x = 0; x < lev_fieldx; x++)
1461 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1462 BorderElement = EL_STEELWALL;
1464 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1470 void FloodFillLevelExt(int from_x, int from_y, int fill_element,
1471 int max_array_fieldx, int max_array_fieldy,
1472 short field[max_array_fieldx][max_array_fieldy],
1473 int max_fieldx, int max_fieldy)
1477 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1478 static int safety = 0;
1480 /* check if starting field still has the desired content */
1481 if (field[from_x][from_y] == fill_element)
1486 if (safety > max_fieldx * max_fieldy)
1487 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1489 old_element = field[from_x][from_y];
1490 field[from_x][from_y] = fill_element;
1492 for (i = 0; i < 4; i++)
1494 x = from_x + check[i][0];
1495 y = from_y + check[i][1];
1497 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1498 FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy,
1499 field, max_fieldx, max_fieldy);
1505 void FloodFillLevel(int from_x, int from_y, int fill_element,
1506 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1507 int max_fieldx, int max_fieldy)
1509 FloodFillLevelExt(from_x, from_y, fill_element,
1510 MAX_LEV_FIELDX, MAX_LEV_FIELDY, field,
1511 max_fieldx, max_fieldy);
1514 void SetRandomAnimationValue(int x, int y)
1516 gfx.anim_random_frame = GfxRandom[x][y];
1519 int getGraphicAnimationFrame(int graphic, int sync_frame)
1521 /* animation synchronized with global frame counter, not move position */
1522 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1523 sync_frame = FrameCounter;
1525 return getAnimationFrame(graphic_info[graphic].anim_frames,
1526 graphic_info[graphic].anim_delay,
1527 graphic_info[graphic].anim_mode,
1528 graphic_info[graphic].anim_start_frame,
1532 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1534 struct GraphicInfo *g = &graphic_info[graphic];
1535 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1537 if (tilesize == gfx.standard_tile_size)
1538 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1539 else if (tilesize == game.tile_size)
1540 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1542 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1545 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1546 boolean get_backside)
1548 struct GraphicInfo *g = &graphic_info[graphic];
1549 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1550 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1552 if (g->offset_y == 0) /* frames are ordered horizontally */
1554 int max_width = g->anim_frames_per_line * g->width;
1555 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1557 *x = pos % max_width;
1558 *y = src_y % g->height + pos / max_width * g->height;
1560 else if (g->offset_x == 0) /* frames are ordered vertically */
1562 int max_height = g->anim_frames_per_line * g->height;
1563 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1565 *x = src_x % g->width + pos / max_height * g->width;
1566 *y = pos % max_height;
1568 else /* frames are ordered diagonally */
1570 *x = src_x + frame * g->offset_x;
1571 *y = src_y + frame * g->offset_y;
1575 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1576 Bitmap **bitmap, int *x, int *y,
1577 boolean get_backside)
1579 struct GraphicInfo *g = &graphic_info[graphic];
1581 // if no graphics defined at all, use fallback graphics
1582 if (g->bitmaps == NULL)
1583 *g = graphic_info[IMG_CHAR_EXCLAM];
1585 // if no in-game graphics defined, always use standard graphic size
1586 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1587 tilesize = TILESIZE;
1589 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1590 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1592 *x = *x * tilesize / g->tile_size;
1593 *y = *y * tilesize / g->tile_size;
1596 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1597 Bitmap **bitmap, int *x, int *y)
1599 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1602 void getFixedGraphicSource(int graphic, int frame,
1603 Bitmap **bitmap, int *x, int *y)
1605 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1608 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1610 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1613 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1614 int *x, int *y, boolean get_backside)
1616 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, 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");
1636 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1639 MarkTileDirty(x, y);
1642 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1645 if (!IN_SCR_FIELD(x, y))
1647 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1648 printf("DrawGraphic(): This should never happen!\n");
1653 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1655 MarkTileDirty(x, y);
1658 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1664 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1666 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1669 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1675 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1676 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1679 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1682 if (!IN_SCR_FIELD(x, y))
1684 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1685 printf("DrawGraphicThruMask(): This should never happen!\n");
1690 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1693 MarkTileDirty(x, y);
1696 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1699 if (!IN_SCR_FIELD(x, y))
1701 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1702 printf("DrawGraphicThruMask(): This should never happen!\n");
1707 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1709 MarkTileDirty(x, y);
1712 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1718 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1720 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1724 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1725 int graphic, int frame)
1730 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1732 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1736 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1738 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1740 MarkTileDirty(x / tilesize, y / tilesize);
1743 void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame,
1746 DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize,
1747 graphic, frame, tilesize);
1748 MarkTileDirty(x / tilesize, y / tilesize);
1751 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1757 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1758 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1761 void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic,
1762 int frame, int tilesize)
1767 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1768 BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1771 void DrawMiniGraphic(int x, int y, int graphic)
1773 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1774 MarkTileDirty(x / 2, y / 2);
1777 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1782 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1783 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1786 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1787 int graphic, int frame,
1788 int cut_mode, int mask_mode)
1793 int width = TILEX, height = TILEY;
1796 if (dx || dy) /* shifted graphic */
1798 if (x < BX1) /* object enters playfield from the left */
1805 else if (x > BX2) /* object enters playfield from the right */
1811 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1817 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1819 else if (dx) /* general horizontal movement */
1820 MarkTileDirty(x + SIGN(dx), y);
1822 if (y < BY1) /* object enters playfield from the top */
1824 if (cut_mode == CUT_BELOW) /* object completely above top border */
1832 else if (y > BY2) /* object enters playfield from the bottom */
1838 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1844 else if (dy > 0 && cut_mode == CUT_ABOVE)
1846 if (y == BY2) /* object completely above bottom border */
1852 MarkTileDirty(x, y + 1);
1853 } /* object leaves playfield to the bottom */
1854 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1856 else if (dy) /* general vertical movement */
1857 MarkTileDirty(x, y + SIGN(dy));
1861 if (!IN_SCR_FIELD(x, y))
1863 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1864 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;
1876 if (width > 0 && height > 0)
1878 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1883 dst_x = FX + x * TILEX_VAR + dx;
1884 dst_y = FY + y * TILEY_VAR + dy;
1886 if (mask_mode == USE_MASKING)
1887 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1890 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1893 MarkTileDirty(x, y);
1897 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1898 int graphic, int frame,
1899 int cut_mode, int mask_mode)
1904 int width = TILEX_VAR, height = TILEY_VAR;
1907 int x2 = x + SIGN(dx);
1908 int y2 = y + SIGN(dy);
1910 /* movement with two-tile animations must be sync'ed with movement position,
1911 not with current GfxFrame (which can be higher when using slow movement) */
1912 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1913 int anim_frames = graphic_info[graphic].anim_frames;
1915 /* (we also need anim_delay here for movement animations with less frames) */
1916 int anim_delay = graphic_info[graphic].anim_delay;
1917 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1919 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1920 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1922 /* re-calculate animation frame for two-tile movement animation */
1923 frame = getGraphicAnimationFrame(graphic, sync_frame);
1925 /* check if movement start graphic inside screen area and should be drawn */
1926 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1928 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1930 dst_x = FX + x1 * TILEX_VAR;
1931 dst_y = FY + y1 * TILEY_VAR;
1933 if (mask_mode == USE_MASKING)
1934 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1937 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1940 MarkTileDirty(x1, y1);
1943 /* check if movement end graphic inside screen area and should be drawn */
1944 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1946 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1948 dst_x = FX + x2 * TILEX_VAR;
1949 dst_y = FY + y2 * TILEY_VAR;
1951 if (mask_mode == USE_MASKING)
1952 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1955 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1958 MarkTileDirty(x2, y2);
1962 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1963 int graphic, int frame,
1964 int cut_mode, int mask_mode)
1968 DrawGraphic(x, y, graphic, frame);
1973 if (graphic_info[graphic].double_movement) /* EM style movement images */
1974 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1976 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1979 static void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy,
1980 int graphic, int frame, int cut_mode)
1982 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1985 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1986 int cut_mode, int mask_mode)
1988 int lx = LEVELX(x), ly = LEVELY(y);
1992 if (IN_LEV_FIELD(lx, ly))
1994 SetRandomAnimationValue(lx, ly);
1996 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1997 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1999 /* do not use double (EM style) movement graphic when not moving */
2000 if (graphic_info[graphic].double_movement && !dx && !dy)
2002 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2003 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2006 else /* border element */
2008 graphic = el2img(element);
2009 frame = getGraphicAnimationFrame(graphic, -1);
2012 if (element == EL_EXPANDABLE_WALL)
2014 boolean left_stopped = FALSE, right_stopped = FALSE;
2016 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2017 left_stopped = TRUE;
2018 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2019 right_stopped = TRUE;
2021 if (left_stopped && right_stopped)
2023 else if (left_stopped)
2025 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2026 frame = graphic_info[graphic].anim_frames - 1;
2028 else if (right_stopped)
2030 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2031 frame = graphic_info[graphic].anim_frames - 1;
2036 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2037 else if (mask_mode == USE_MASKING)
2038 DrawGraphicThruMask(x, y, graphic, frame);
2040 DrawGraphic(x, y, graphic, frame);
2043 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2044 int cut_mode, int mask_mode)
2046 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2047 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2048 cut_mode, mask_mode);
2051 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2054 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2057 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2060 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2063 void DrawLevelElementThruMask(int x, int y, int element)
2065 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2068 void DrawLevelFieldThruMask(int x, int y)
2070 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2073 /* !!! implementation of quicksand is totally broken !!! */
2074 #define IS_CRUMBLED_TILE(x, y, e) \
2075 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2076 !IS_MOVING(x, y) || \
2077 (e) == EL_QUICKSAND_EMPTYING || \
2078 (e) == EL_QUICKSAND_FAST_EMPTYING))
2080 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2085 int width, height, cx, cy;
2086 int sx = SCREENX(x), sy = SCREENY(y);
2087 int crumbled_border_size = graphic_info[graphic].border_size;
2088 int crumbled_tile_size = graphic_info[graphic].tile_size;
2089 int crumbled_border_size_var =
2090 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2093 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2095 for (i = 1; i < 4; i++)
2097 int dxx = (i & 1 ? dx : 0);
2098 int dyy = (i & 2 ? dy : 0);
2101 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2104 /* check if neighbour field is of same crumble type */
2105 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2106 graphic_info[graphic].class ==
2107 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2109 /* return if check prevents inner corner */
2110 if (same == (dxx == dx && dyy == dy))
2114 /* if we reach this point, we have an inner corner */
2116 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2118 width = crumbled_border_size_var;
2119 height = crumbled_border_size_var;
2120 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2121 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2123 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2124 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2127 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2132 int width, height, bx, by, cx, cy;
2133 int sx = SCREENX(x), sy = SCREENY(y);
2134 int crumbled_border_size = graphic_info[graphic].border_size;
2135 int crumbled_tile_size = graphic_info[graphic].tile_size;
2136 int crumbled_border_size_var =
2137 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2138 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2141 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2143 /* draw simple, sloppy, non-corner-accurate crumbled border */
2145 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2146 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2147 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2148 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2150 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
2151 FX + sx * TILEX_VAR + cx,
2152 FY + sy * TILEY_VAR + cy);
2154 /* (remaining middle border part must be at least as big as corner part) */
2155 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2156 crumbled_border_size_var >= TILESIZE_VAR / 3)
2159 /* correct corners of crumbled border, if needed */
2161 for (i = -1; i <= 1; i += 2)
2163 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2164 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2165 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2168 /* check if neighbour field is of same crumble type */
2169 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2170 graphic_info[graphic].class ==
2171 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2173 /* no crumbled corner, but continued crumbled border */
2175 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2176 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2177 int b1 = (i == 1 ? crumbled_border_size_var :
2178 TILESIZE_VAR - 2 * crumbled_border_size_var);
2180 width = crumbled_border_size_var;
2181 height = crumbled_border_size_var;
2183 if (dir == 1 || dir == 2)
2198 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2200 FX + sx * TILEX_VAR + cx,
2201 FY + sy * TILEY_VAR + cy);
2206 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2208 int sx = SCREENX(x), sy = SCREENY(y);
2211 static int xy[4][2] =
2219 if (!IN_LEV_FIELD(x, y))
2222 element = TILE_GFX_ELEMENT(x, y);
2224 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2226 if (!IN_SCR_FIELD(sx, sy))
2229 /* crumble field borders towards direct neighbour fields */
2230 for (i = 0; i < 4; i++)
2232 int xx = x + xy[i][0];
2233 int yy = y + xy[i][1];
2235 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2238 /* check if neighbour field is of same crumble type */
2239 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2240 graphic_info[graphic].class ==
2241 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2244 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2247 /* crumble inner field corners towards corner neighbour fields */
2248 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2249 graphic_info[graphic].anim_frames == 2)
2251 for (i = 0; i < 4; i++)
2253 int dx = (i & 1 ? +1 : -1);
2254 int dy = (i & 2 ? +1 : -1);
2256 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2260 MarkTileDirty(sx, sy);
2262 else /* center field is not crumbled -- crumble neighbour fields */
2264 /* crumble field borders of direct neighbour fields */
2265 for (i = 0; i < 4; i++)
2267 int xx = x + xy[i][0];
2268 int yy = y + xy[i][1];
2269 int sxx = sx + xy[i][0];
2270 int syy = sy + xy[i][1];
2272 if (!IN_LEV_FIELD(xx, yy) ||
2273 !IN_SCR_FIELD(sxx, syy))
2276 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2279 element = TILE_GFX_ELEMENT(xx, yy);
2281 if (!IS_CRUMBLED_TILE(xx, yy, element))
2284 graphic = el_act2crm(element, ACTION_DEFAULT);
2286 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2288 MarkTileDirty(sxx, syy);
2291 /* crumble inner field corners of corner neighbour fields */
2292 for (i = 0; i < 4; i++)
2294 int dx = (i & 1 ? +1 : -1);
2295 int dy = (i & 2 ? +1 : -1);
2301 if (!IN_LEV_FIELD(xx, yy) ||
2302 !IN_SCR_FIELD(sxx, syy))
2305 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2308 element = TILE_GFX_ELEMENT(xx, yy);
2310 if (!IS_CRUMBLED_TILE(xx, yy, element))
2313 graphic = el_act2crm(element, ACTION_DEFAULT);
2315 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2316 graphic_info[graphic].anim_frames == 2)
2317 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2319 MarkTileDirty(sxx, syy);
2324 void DrawLevelFieldCrumbled(int x, int y)
2328 if (!IN_LEV_FIELD(x, y))
2331 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2332 GfxElement[x][y] != EL_UNDEFINED &&
2333 GFX_CRUMBLED(GfxElement[x][y]))
2335 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2340 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2342 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2345 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2348 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2349 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2350 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2351 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2352 int sx = SCREENX(x), sy = SCREENY(y);
2354 DrawGraphic(sx, sy, graphic1, frame1);
2355 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2358 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2360 int sx = SCREENX(x), sy = SCREENY(y);
2361 static int xy[4][2] =
2370 /* crumble direct neighbour fields (required for field borders) */
2371 for (i = 0; i < 4; i++)
2373 int xx = x + xy[i][0];
2374 int yy = y + xy[i][1];
2375 int sxx = sx + xy[i][0];
2376 int syy = sy + xy[i][1];
2378 if (!IN_LEV_FIELD(xx, yy) ||
2379 !IN_SCR_FIELD(sxx, syy) ||
2380 !GFX_CRUMBLED(Feld[xx][yy]) ||
2384 DrawLevelField(xx, yy);
2387 /* crumble corner neighbour fields (required for inner field corners) */
2388 for (i = 0; i < 4; i++)
2390 int dx = (i & 1 ? +1 : -1);
2391 int dy = (i & 2 ? +1 : -1);
2397 if (!IN_LEV_FIELD(xx, yy) ||
2398 !IN_SCR_FIELD(sxx, syy) ||
2399 !GFX_CRUMBLED(Feld[xx][yy]) ||
2403 int element = TILE_GFX_ELEMENT(xx, yy);
2404 int graphic = el_act2crm(element, ACTION_DEFAULT);
2406 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2407 graphic_info[graphic].anim_frames == 2)
2408 DrawLevelField(xx, yy);
2412 static int getBorderElement(int x, int y)
2416 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2417 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2418 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2419 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2420 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2421 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2422 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2424 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2425 int steel_position = (x == -1 && y == -1 ? 0 :
2426 x == lev_fieldx && y == -1 ? 1 :
2427 x == -1 && y == lev_fieldy ? 2 :
2428 x == lev_fieldx && y == lev_fieldy ? 3 :
2429 x == -1 || x == lev_fieldx ? 4 :
2430 y == -1 || y == lev_fieldy ? 5 : 6);
2432 return border[steel_position][steel_type];
2435 void DrawScreenElement(int x, int y, int element)
2437 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2438 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2441 void DrawLevelElement(int x, int y, int element)
2443 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2444 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2447 void DrawScreenField(int x, int y)
2449 int lx = LEVELX(x), ly = LEVELY(y);
2450 int element, content;
2452 if (!IN_LEV_FIELD(lx, ly))
2454 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2457 element = getBorderElement(lx, ly);
2459 DrawScreenElement(x, y, element);
2464 element = Feld[lx][ly];
2465 content = Store[lx][ly];
2467 if (IS_MOVING(lx, ly))
2469 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2470 boolean cut_mode = NO_CUTTING;
2472 if (element == EL_QUICKSAND_EMPTYING ||
2473 element == EL_QUICKSAND_FAST_EMPTYING ||
2474 element == EL_MAGIC_WALL_EMPTYING ||
2475 element == EL_BD_MAGIC_WALL_EMPTYING ||
2476 element == EL_DC_MAGIC_WALL_EMPTYING ||
2477 element == EL_AMOEBA_DROPPING)
2478 cut_mode = CUT_ABOVE;
2479 else if (element == EL_QUICKSAND_FILLING ||
2480 element == EL_QUICKSAND_FAST_FILLING ||
2481 element == EL_MAGIC_WALL_FILLING ||
2482 element == EL_BD_MAGIC_WALL_FILLING ||
2483 element == EL_DC_MAGIC_WALL_FILLING)
2484 cut_mode = CUT_BELOW;
2486 if (cut_mode == CUT_ABOVE)
2487 DrawScreenElement(x, y, element);
2489 DrawScreenElement(x, y, EL_EMPTY);
2492 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2493 else if (cut_mode == NO_CUTTING)
2494 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2497 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2499 if (cut_mode == CUT_BELOW &&
2500 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2501 DrawLevelElement(lx, ly + 1, element);
2504 if (content == EL_ACID)
2506 int dir = MovDir[lx][ly];
2507 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2508 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2510 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2512 // prevent target field from being drawn again (but without masking)
2513 // (this would happen if target field is scanned after moving element)
2514 Stop[newlx][newly] = TRUE;
2517 else if (IS_BLOCKED(lx, ly))
2522 boolean cut_mode = NO_CUTTING;
2523 int element_old, content_old;
2525 Blocked2Moving(lx, ly, &oldx, &oldy);
2528 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2529 MovDir[oldx][oldy] == MV_RIGHT);
2531 element_old = Feld[oldx][oldy];
2532 content_old = Store[oldx][oldy];
2534 if (element_old == EL_QUICKSAND_EMPTYING ||
2535 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2536 element_old == EL_MAGIC_WALL_EMPTYING ||
2537 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2538 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2539 element_old == EL_AMOEBA_DROPPING)
2540 cut_mode = CUT_ABOVE;
2542 DrawScreenElement(x, y, EL_EMPTY);
2545 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2547 else if (cut_mode == NO_CUTTING)
2548 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2551 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2554 else if (IS_DRAWABLE(element))
2555 DrawScreenElement(x, y, element);
2557 DrawScreenElement(x, y, EL_EMPTY);
2560 void DrawLevelField(int x, int y)
2562 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2563 DrawScreenField(SCREENX(x), SCREENY(y));
2564 else if (IS_MOVING(x, y))
2568 Moving2Blocked(x, y, &newx, &newy);
2569 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2570 DrawScreenField(SCREENX(newx), SCREENY(newy));
2572 else if (IS_BLOCKED(x, y))
2576 Blocked2Moving(x, y, &oldx, &oldy);
2577 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2578 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2582 static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize,
2583 int (*el2img_function)(int), boolean masked,
2584 int element_bits_draw)
2586 int element_base = map_mm_wall_element(element);
2587 int element_bits = (IS_DF_WALL(element) ?
2588 element - EL_DF_WALL_START :
2589 IS_MM_WALL(element) ?
2590 element - EL_MM_WALL_START : EL_EMPTY) & 0x000f;
2591 int graphic = el2img_function(element_base);
2592 int tilesize_draw = tilesize / 2;
2597 getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y);
2599 for (i = 0; i < 4; i++)
2601 int dst_draw_x = dst_x + (i % 2) * tilesize_draw;
2602 int dst_draw_y = dst_y + (i / 2) * tilesize_draw;
2604 if (!(element_bits_draw & (1 << i)))
2607 if (element_bits & (1 << i))
2610 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y,
2611 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2613 BlitBitmap(src_bitmap, drawto, src_x, src_y,
2614 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2619 ClearRectangle(drawto, dst_draw_x, dst_draw_y,
2620 tilesize_draw, tilesize_draw);
2625 void DrawSizedWallParts_MM(int x, int y, int element, int tilesize,
2626 boolean masked, int element_bits_draw)
2628 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2629 element, tilesize, el2edimg, masked, element_bits_draw);
2632 static void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize,
2633 int (*el2img_function)(int))
2635 DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE,
2639 static void DrawSizedElementExt(int x, int y, int element, int tilesize,
2642 if (IS_MM_WALL(element))
2644 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2645 element, tilesize, el2edimg, masked, 0x000f);
2649 int graphic = el2edimg(element);
2652 DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
2654 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2658 void DrawSizedElement(int x, int y, int element, int tilesize)
2660 DrawSizedElementExt(x, y, element, tilesize, FALSE);
2663 void DrawSizedElementThruMask(int x, int y, int element, int tilesize)
2665 DrawSizedElementExt(x, y, element, tilesize, TRUE);
2668 void DrawMiniElement(int x, int y, int element)
2672 graphic = el2edimg(element);
2673 DrawMiniGraphic(x, y, graphic);
2676 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2679 int x = sx + scroll_x, y = sy + scroll_y;
2681 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2682 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2683 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2684 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2686 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2689 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2691 int x = sx + scroll_x, y = sy + scroll_y;
2693 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2694 DrawMiniElement(sx, sy, EL_EMPTY);
2695 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2696 DrawMiniElement(sx, sy, Feld[x][y]);
2698 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2701 static void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2702 int x, int y, int xsize, int ysize,
2703 int tile_width, int tile_height)
2707 int dst_x = startx + x * tile_width;
2708 int dst_y = starty + y * tile_height;
2709 int width = graphic_info[graphic].width;
2710 int height = graphic_info[graphic].height;
2711 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2712 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2713 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2714 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2715 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2716 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2717 boolean draw_masked = graphic_info[graphic].draw_masked;
2719 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2721 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2723 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2727 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2728 inner_sx + (x - 1) * tile_width % inner_width);
2729 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2730 inner_sy + (y - 1) * tile_height % inner_height);
2733 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2736 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2740 static void DrawEnvelopeBackground(int graphic, int startx, int starty,
2741 int x, int y, int xsize, int ysize,
2744 int font_width = getFontWidth(font_nr);
2745 int font_height = getFontHeight(font_nr);
2747 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2748 font_width, font_height);
2751 static void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2753 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2754 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2755 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2756 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2757 boolean no_delay = (tape.warp_forward);
2758 unsigned int anim_delay = 0;
2759 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2760 int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
2761 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2762 int font_width = getFontWidth(font_nr);
2763 int font_height = getFontHeight(font_nr);
2764 int max_xsize = level.envelope[envelope_nr].xsize;
2765 int max_ysize = level.envelope[envelope_nr].ysize;
2766 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2767 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2768 int xend = max_xsize;
2769 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2770 int xstep = (xstart < xend ? 1 : 0);
2771 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2773 int end = MAX(xend - xstart, yend - ystart);
2776 for (i = start; i <= end; i++)
2778 int last_frame = end; // last frame of this "for" loop
2779 int x = xstart + i * xstep;
2780 int y = ystart + i * ystep;
2781 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2782 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2783 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2784 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2787 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2789 BlitScreenToBitmap(backbuffer);
2791 SetDrawtoField(DRAW_TO_BACKBUFFER);
2793 for (yy = 0; yy < ysize; yy++)
2794 for (xx = 0; xx < xsize; xx++)
2795 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2797 DrawTextBuffer(sx + font_width, sy + font_height,
2798 level.envelope[envelope_nr].text, font_nr, max_xsize,
2799 xsize - 2, ysize - 2, 0, mask_mode,
2800 level.envelope[envelope_nr].autowrap,
2801 level.envelope[envelope_nr].centered, FALSE);
2803 redraw_mask |= REDRAW_FIELD;
2806 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2809 ClearAutoRepeatKeyEvents();
2812 void ShowEnvelope(int envelope_nr)
2814 int element = EL_ENVELOPE_1 + envelope_nr;
2815 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2816 int sound_opening = element_info[element].sound[ACTION_OPENING];
2817 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2818 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2819 boolean no_delay = (tape.warp_forward);
2820 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2821 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2822 int anim_mode = graphic_info[graphic].anim_mode;
2823 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2824 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2826 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2828 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2830 if (anim_mode == ANIM_DEFAULT)
2831 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2833 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2836 Delay(wait_delay_value);
2838 WaitForEventToContinue();
2840 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2842 if (anim_mode != ANIM_NONE)
2843 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2845 if (anim_mode == ANIM_DEFAULT)
2846 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2848 game.envelope_active = FALSE;
2850 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2852 redraw_mask |= REDRAW_FIELD;
2856 static void setRequestBasePosition(int *x, int *y)
2858 int sx_base, sy_base;
2860 if (request.x != -1)
2861 sx_base = request.x;
2862 else if (request.align == ALIGN_LEFT)
2864 else if (request.align == ALIGN_RIGHT)
2865 sx_base = SX + SXSIZE;
2867 sx_base = SX + SXSIZE / 2;
2869 if (request.y != -1)
2870 sy_base = request.y;
2871 else if (request.valign == VALIGN_TOP)
2873 else if (request.valign == VALIGN_BOTTOM)
2874 sy_base = SY + SYSIZE;
2876 sy_base = SY + SYSIZE / 2;
2882 static void setRequestPositionExt(int *x, int *y, int width, int height,
2883 boolean add_border_size)
2885 int border_size = request.border_size;
2886 int sx_base, sy_base;
2889 setRequestBasePosition(&sx_base, &sy_base);
2891 if (request.align == ALIGN_LEFT)
2893 else if (request.align == ALIGN_RIGHT)
2894 sx = sx_base - width;
2896 sx = sx_base - width / 2;
2898 if (request.valign == VALIGN_TOP)
2900 else if (request.valign == VALIGN_BOTTOM)
2901 sy = sy_base - height;
2903 sy = sy_base - height / 2;
2905 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2906 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2908 if (add_border_size)
2918 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2920 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2923 static void DrawEnvelopeRequest(char *text)
2925 char *text_final = text;
2926 char *text_door_style = NULL;
2927 int graphic = IMG_BACKGROUND_REQUEST;
2928 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2929 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2930 int font_nr = FONT_REQUEST;
2931 int font_width = getFontWidth(font_nr);
2932 int font_height = getFontHeight(font_nr);
2933 int border_size = request.border_size;
2934 int line_spacing = request.line_spacing;
2935 int line_height = font_height + line_spacing;
2936 int max_text_width = request.width - 2 * border_size;
2937 int max_text_height = request.height - 2 * border_size;
2938 int line_length = max_text_width / font_width;
2939 int max_lines = max_text_height / line_height;
2940 int text_width = line_length * font_width;
2941 int width = request.width;
2942 int height = request.height;
2943 int tile_size = MAX(request.step_offset, 1);
2944 int x_steps = width / tile_size;
2945 int y_steps = height / tile_size;
2946 int sx_offset = border_size;
2947 int sy_offset = border_size;
2951 if (request.centered)
2952 sx_offset = (request.width - text_width) / 2;
2954 if (request.wrap_single_words && !request.autowrap)
2956 char *src_text_ptr, *dst_text_ptr;
2958 text_door_style = checked_malloc(2 * strlen(text) + 1);
2960 src_text_ptr = text;
2961 dst_text_ptr = text_door_style;
2963 while (*src_text_ptr)
2965 if (*src_text_ptr == ' ' ||
2966 *src_text_ptr == '?' ||
2967 *src_text_ptr == '!')
2968 *dst_text_ptr++ = '\n';
2970 if (*src_text_ptr != ' ')
2971 *dst_text_ptr++ = *src_text_ptr;
2976 *dst_text_ptr = '\0';
2978 text_final = text_door_style;
2981 setRequestPosition(&sx, &sy, FALSE);
2983 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2985 for (y = 0; y < y_steps; y++)
2986 for (x = 0; x < x_steps; x++)
2987 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2988 x, y, x_steps, y_steps,
2989 tile_size, tile_size);
2991 /* force DOOR font inside door area */
2992 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2994 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2995 line_length, -1, max_lines, line_spacing, mask_mode,
2996 request.autowrap, request.centered, FALSE);
3000 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3001 RedrawGadget(tool_gadget[i]);
3003 // store readily prepared envelope request for later use when animating
3004 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3006 if (text_door_style)
3007 free(text_door_style);
3010 static void AnimateEnvelopeRequest(int anim_mode, int action)
3012 int graphic = IMG_BACKGROUND_REQUEST;
3013 boolean draw_masked = graphic_info[graphic].draw_masked;
3014 int delay_value_normal = request.step_delay;
3015 int delay_value_fast = delay_value_normal / 2;
3016 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3017 boolean no_delay = (tape.warp_forward);
3018 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3019 int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2);
3020 unsigned int anim_delay = 0;
3022 int tile_size = MAX(request.step_offset, 1);
3023 int max_xsize = request.width / tile_size;
3024 int max_ysize = request.height / tile_size;
3025 int max_xsize_inner = max_xsize - 2;
3026 int max_ysize_inner = max_ysize - 2;
3028 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3029 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3030 int xend = max_xsize_inner;
3031 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3032 int xstep = (xstart < xend ? 1 : 0);
3033 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3035 int end = MAX(xend - xstart, yend - ystart);
3038 if (setup.quick_doors)
3045 for (i = start; i <= end; i++)
3047 int last_frame = end; // last frame of this "for" loop
3048 int x = xstart + i * xstep;
3049 int y = ystart + i * ystep;
3050 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3051 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3052 int xsize_size_left = (xsize - 1) * tile_size;
3053 int ysize_size_top = (ysize - 1) * tile_size;
3054 int max_xsize_pos = (max_xsize - 1) * tile_size;
3055 int max_ysize_pos = (max_ysize - 1) * tile_size;
3056 int width = xsize * tile_size;
3057 int height = ysize * tile_size;
3062 setRequestPosition(&src_x, &src_y, FALSE);
3063 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
3065 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3067 for (yy = 0; yy < 2; yy++)
3069 for (xx = 0; xx < 2; xx++)
3071 int src_xx = src_x + xx * max_xsize_pos;
3072 int src_yy = src_y + yy * max_ysize_pos;
3073 int dst_xx = dst_x + xx * xsize_size_left;
3074 int dst_yy = dst_y + yy * ysize_size_top;
3075 int xx_size = (xx ? tile_size : xsize_size_left);
3076 int yy_size = (yy ? tile_size : ysize_size_top);
3079 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
3080 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3082 BlitBitmap(bitmap_db_store_2, backbuffer,
3083 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3087 redraw_mask |= REDRAW_FIELD;
3091 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
3094 ClearAutoRepeatKeyEvents();
3097 static void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3099 int graphic = IMG_BACKGROUND_REQUEST;
3100 int sound_opening = SND_REQUEST_OPENING;
3101 int sound_closing = SND_REQUEST_CLOSING;
3102 int anim_mode_1 = request.anim_mode; /* (higher priority) */
3103 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
3104 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
3105 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3106 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3108 if (game_status == GAME_MODE_PLAYING)
3109 BlitScreenToBitmap(backbuffer);
3111 SetDrawtoField(DRAW_TO_BACKBUFFER);
3113 // SetDrawBackgroundMask(REDRAW_NONE);
3115 if (action == ACTION_OPENING)
3117 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3119 if (req_state & REQ_ASK)
3121 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3122 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3124 else if (req_state & REQ_CONFIRM)
3126 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3128 else if (req_state & REQ_PLAYER)
3130 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3131 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3132 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3133 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3136 DrawEnvelopeRequest(text);
3139 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3141 if (action == ACTION_OPENING)
3143 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3145 if (anim_mode == ANIM_DEFAULT)
3146 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3148 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3152 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3154 if (anim_mode != ANIM_NONE)
3155 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3157 if (anim_mode == ANIM_DEFAULT)
3158 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3161 game.envelope_active = FALSE;
3163 if (action == ACTION_CLOSING)
3164 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3166 // SetDrawBackgroundMask(last_draw_background_mask);
3168 redraw_mask |= REDRAW_FIELD;
3172 if (action == ACTION_CLOSING &&
3173 game_status == GAME_MODE_PLAYING &&
3174 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3175 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3178 static void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3180 if (IS_MM_WALL(element))
3182 DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg);
3188 int graphic = el2preimg(element);
3190 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3191 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize,
3196 void DrawLevel(int draw_background_mask)
3200 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3201 SetDrawBackgroundMask(draw_background_mask);
3205 for (x = BX1; x <= BX2; x++)
3206 for (y = BY1; y <= BY2; y++)
3207 DrawScreenField(x, y);
3209 redraw_mask |= REDRAW_FIELD;
3212 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
3217 for (x = 0; x < size_x; x++)
3218 for (y = 0; y < size_y; y++)
3219 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
3221 redraw_mask |= REDRAW_FIELD;
3224 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3228 for (x = 0; x < size_x; x++)
3229 for (y = 0; y < size_y; y++)
3230 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3232 redraw_mask |= REDRAW_FIELD;
3235 static void DrawPreviewLevelPlayfield(int from_x, int from_y)
3237 boolean show_level_border = (BorderElement != EL_EMPTY);
3238 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3239 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3240 int tile_size = preview.tile_size;
3241 int preview_width = preview.xsize * tile_size;
3242 int preview_height = preview.ysize * tile_size;
3243 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3244 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3245 int real_preview_width = real_preview_xsize * tile_size;
3246 int real_preview_height = real_preview_ysize * tile_size;
3247 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3248 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3251 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3254 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3256 dst_x += (preview_width - real_preview_width) / 2;
3257 dst_y += (preview_height - real_preview_height) / 2;
3259 for (x = 0; x < real_preview_xsize; x++)
3261 for (y = 0; y < real_preview_ysize; y++)
3263 int lx = from_x + x + (show_level_border ? -1 : 0);
3264 int ly = from_y + y + (show_level_border ? -1 : 0);
3265 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3266 getBorderElement(lx, ly));
3268 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3269 element, tile_size);
3273 redraw_mask |= REDRAW_FIELD;
3276 #define MICROLABEL_EMPTY 0
3277 #define MICROLABEL_LEVEL_NAME 1
3278 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3279 #define MICROLABEL_LEVEL_AUTHOR 3
3280 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3281 #define MICROLABEL_IMPORTED_FROM 5
3282 #define MICROLABEL_IMPORTED_BY_HEAD 6
3283 #define MICROLABEL_IMPORTED_BY 7
3285 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3287 int max_text_width = SXSIZE;
3288 int font_width = getFontWidth(font_nr);
3290 if (pos->align == ALIGN_CENTER)
3291 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3292 else if (pos->align == ALIGN_RIGHT)
3293 max_text_width = pos->x;
3295 max_text_width = SXSIZE - pos->x;
3297 return max_text_width / font_width;
3300 static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos)
3302 char label_text[MAX_OUTPUT_LINESIZE + 1];
3303 int max_len_label_text;
3304 int font_nr = pos->font;
3307 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3310 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3311 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3312 mode == MICROLABEL_IMPORTED_BY_HEAD)
3313 font_nr = pos->font_alt;
3315 max_len_label_text = getMaxTextLength(pos, font_nr);
3317 if (pos->size != -1)
3318 max_len_label_text = pos->size;
3320 for (i = 0; i < max_len_label_text; i++)
3321 label_text[i] = ' ';
3322 label_text[max_len_label_text] = '\0';
3324 if (strlen(label_text) > 0)
3325 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3328 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3329 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3330 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3331 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3332 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3333 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3334 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3335 max_len_label_text);
3336 label_text[max_len_label_text] = '\0';
3338 if (strlen(label_text) > 0)
3339 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3341 redraw_mask |= REDRAW_FIELD;
3344 static void DrawPreviewLevelLabel(int mode)
3346 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2);
3349 static void DrawPreviewLevelInfo(int mode)
3351 if (mode == MICROLABEL_LEVEL_NAME)
3352 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name);
3353 else if (mode == MICROLABEL_LEVEL_AUTHOR)
3354 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author);
3357 static void DrawPreviewLevelExt(boolean restart)
3359 static unsigned int scroll_delay = 0;
3360 static unsigned int label_delay = 0;
3361 static int from_x, from_y, scroll_direction;
3362 static int label_state, label_counter;
3363 unsigned int scroll_delay_value = preview.step_delay;
3364 boolean show_level_border = (BorderElement != EL_EMPTY);
3365 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3366 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3373 if (preview.anim_mode == ANIM_CENTERED)
3375 if (level_xsize > preview.xsize)
3376 from_x = (level_xsize - preview.xsize) / 2;
3377 if (level_ysize > preview.ysize)
3378 from_y = (level_ysize - preview.ysize) / 2;
3381 from_x += preview.xoffset;
3382 from_y += preview.yoffset;
3384 scroll_direction = MV_RIGHT;
3388 DrawPreviewLevelPlayfield(from_x, from_y);
3389 DrawPreviewLevelLabel(label_state);
3391 DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME);
3392 DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR);
3394 /* initialize delay counters */
3395 DelayReached(&scroll_delay, 0);
3396 DelayReached(&label_delay, 0);
3398 if (leveldir_current->name)
3400 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3401 char label_text[MAX_OUTPUT_LINESIZE + 1];
3402 int font_nr = pos->font;
3403 int max_len_label_text = getMaxTextLength(pos, font_nr);
3405 if (pos->size != -1)
3406 max_len_label_text = pos->size;
3408 strncpy(label_text, leveldir_current->name, max_len_label_text);
3409 label_text[max_len_label_text] = '\0';
3411 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3412 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3418 /* scroll preview level, if needed */
3419 if (preview.anim_mode != ANIM_NONE &&
3420 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3421 DelayReached(&scroll_delay, scroll_delay_value))
3423 switch (scroll_direction)
3428 from_x -= preview.step_offset;
3429 from_x = (from_x < 0 ? 0 : from_x);
3432 scroll_direction = MV_UP;
3436 if (from_x < level_xsize - preview.xsize)
3438 from_x += preview.step_offset;
3439 from_x = (from_x > level_xsize - preview.xsize ?
3440 level_xsize - preview.xsize : from_x);
3443 scroll_direction = MV_DOWN;
3449 from_y -= preview.step_offset;
3450 from_y = (from_y < 0 ? 0 : from_y);
3453 scroll_direction = MV_RIGHT;
3457 if (from_y < level_ysize - preview.ysize)
3459 from_y += preview.step_offset;
3460 from_y = (from_y > level_ysize - preview.ysize ?
3461 level_ysize - preview.ysize : from_y);
3464 scroll_direction = MV_LEFT;
3471 DrawPreviewLevelPlayfield(from_x, from_y);
3474 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3475 /* redraw micro level label, if needed */
3476 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3477 !strEqual(level.author, ANONYMOUS_NAME) &&
3478 !strEqual(level.author, leveldir_current->name) &&
3479 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3481 int max_label_counter = 23;
3483 if (leveldir_current->imported_from != NULL &&
3484 strlen(leveldir_current->imported_from) > 0)
3485 max_label_counter += 14;
3486 if (leveldir_current->imported_by != NULL &&
3487 strlen(leveldir_current->imported_by) > 0)
3488 max_label_counter += 14;
3490 label_counter = (label_counter + 1) % max_label_counter;
3491 label_state = (label_counter >= 0 && label_counter <= 7 ?
3492 MICROLABEL_LEVEL_NAME :
3493 label_counter >= 9 && label_counter <= 12 ?
3494 MICROLABEL_LEVEL_AUTHOR_HEAD :
3495 label_counter >= 14 && label_counter <= 21 ?
3496 MICROLABEL_LEVEL_AUTHOR :
3497 label_counter >= 23 && label_counter <= 26 ?
3498 MICROLABEL_IMPORTED_FROM_HEAD :
3499 label_counter >= 28 && label_counter <= 35 ?
3500 MICROLABEL_IMPORTED_FROM :
3501 label_counter >= 37 && label_counter <= 40 ?
3502 MICROLABEL_IMPORTED_BY_HEAD :
3503 label_counter >= 42 && label_counter <= 49 ?
3504 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3506 if (leveldir_current->imported_from == NULL &&
3507 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3508 label_state == MICROLABEL_IMPORTED_FROM))
3509 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3510 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3512 DrawPreviewLevelLabel(label_state);
3516 static void DrawPreviewPlayers(void)
3518 if (game_status != GAME_MODE_MAIN)
3521 if (!network.enabled && !setup.team_mode)
3524 boolean player_found[MAX_PLAYERS];
3525 int num_players = 0;
3528 for (i = 0; i < MAX_PLAYERS; i++)
3529 player_found[i] = FALSE;
3531 /* check which players can be found in the level (simple approach) */
3532 for (x = 0; x < lev_fieldx; x++)
3534 for (y = 0; y < lev_fieldy; y++)
3536 int element = level.field[x][y];
3538 if (ELEM_IS_PLAYER(element))
3540 int player_nr = GET_PLAYER_NR(element);
3542 player_nr = MIN(MAX(0, player_nr), MAX_PLAYERS - 1);
3544 if (!player_found[player_nr])
3547 player_found[player_nr] = TRUE;
3552 struct TextPosInfo *pos = &menu.main.preview_players;
3553 int tile_size = pos->tile_size;
3554 int border_size = pos->border_size;
3555 int player_xoffset_raw = (pos->vertical ? 0 : tile_size + border_size);
3556 int player_yoffset_raw = (pos->vertical ? tile_size + border_size : 0);
3557 int player_xoffset = (pos->xoffset != -1 ? pos->xoffset : player_xoffset_raw);
3558 int player_yoffset = (pos->yoffset != -1 ? pos->yoffset : player_yoffset_raw);
3559 int max_players_width = (MAX_PLAYERS - 1) * player_xoffset + tile_size;
3560 int max_players_height = (MAX_PLAYERS - 1) * player_yoffset + tile_size;
3561 int all_players_width = (num_players - 1) * player_xoffset + tile_size;
3562 int all_players_height = (num_players - 1) * player_yoffset + tile_size;
3563 int max_xpos = SX + ALIGNED_XPOS(pos->x, max_players_width, pos->align);
3564 int max_ypos = SY + ALIGNED_YPOS(pos->y, max_players_height, pos->valign);
3565 int xpos = SX + ALIGNED_XPOS(pos->x, all_players_width, pos->align);
3566 int ypos = SY + ALIGNED_YPOS(pos->y, all_players_height, pos->valign);
3568 /* clear area in which the players will be drawn */
3569 ClearRectangleOnBackground(drawto, max_xpos, max_ypos,
3570 max_players_width, max_players_height);
3572 /* only draw players if level is suited for team mode */
3573 if (num_players < 2)
3576 /* draw all players that were found in the level */
3577 for (i = 0; i < MAX_PLAYERS; i++)
3579 if (player_found[i])
3581 int graphic = el2img(EL_PLAYER_1 + i);
3583 DrawSizedGraphicThruMaskExt(drawto, xpos, ypos, graphic, 0, tile_size);
3585 xpos += player_xoffset;
3586 ypos += player_yoffset;
3591 void DrawPreviewLevelInitial(void)
3593 DrawPreviewLevelExt(TRUE);
3594 DrawPreviewPlayers();
3597 void DrawPreviewLevelAnimation(void)
3599 DrawPreviewLevelExt(FALSE);
3602 static void DrawNetworkPlayer(int x, int y, int player_nr, int tile_size,
3603 int border_size, int font_nr)
3605 int graphic = el2img(EL_PLAYER_1 + player_nr);
3606 int font_height = getFontHeight(font_nr);
3607 int player_height = MAX(tile_size, font_height);
3608 int xoffset_text = tile_size + border_size;
3609 int yoffset_text = (player_height - font_height) / 2;
3610 int yoffset_graphic = (player_height - tile_size) / 2;
3611 char *player_name = getNetworkPlayerName(player_nr + 1);
3613 DrawSizedGraphicThruMaskExt(drawto, x, y + yoffset_graphic, graphic, 0,
3615 DrawText(x + xoffset_text, y + yoffset_text, player_name, font_nr);
3618 static void DrawNetworkPlayersExt(boolean force)
3620 if (game_status != GAME_MODE_MAIN)
3623 if (!network.connected && !force)
3626 int num_players = 0;
3629 for (i = 0; i < MAX_PLAYERS; i++)
3630 if (stored_player[i].connected_network)
3633 struct TextPosInfo *pos = &menu.main.network_players;
3634 int tile_size = pos->tile_size;
3635 int border_size = pos->border_size;
3636 int xoffset_text = tile_size + border_size;
3637 int font_nr = pos->font;
3638 int font_width = getFontWidth(font_nr);
3639 int font_height = getFontHeight(font_nr);
3640 int player_height = MAX(tile_size, font_height);
3641 int player_yoffset = player_height + border_size;
3642 int max_players_width = xoffset_text + MAX_PLAYER_NAME_LEN * font_width;
3643 int max_players_height = MAX_PLAYERS * player_yoffset - border_size;
3644 int all_players_height = num_players * player_yoffset - border_size;
3645 int max_xpos = SX + ALIGNED_XPOS(pos->x, max_players_width, pos->align);
3646 int max_ypos = SY + ALIGNED_YPOS(pos->y, max_players_height, pos->valign);
3647 int ypos = SY + ALIGNED_YPOS(pos->y, all_players_height, pos->valign);
3649 ClearRectangleOnBackground(drawto, max_xpos, max_ypos,
3650 max_players_width, max_players_height);
3652 /* first draw local network player ... */
3653 for (i = 0; i < MAX_PLAYERS; i++)
3655 if (stored_player[i].connected_network &&
3656 stored_player[i].connected_locally)
3658 char *player_name = getNetworkPlayerName(i + 1);
3659 int player_width = xoffset_text + getTextWidth(player_name, font_nr);
3660 int xpos = SX + ALIGNED_XPOS(pos->x, player_width, pos->align);
3662 DrawNetworkPlayer(xpos, ypos, i, tile_size, border_size, font_nr);
3664 ypos += player_yoffset;
3668 /* ... then draw all other network players */
3669 for (i = 0; i < MAX_PLAYERS; i++)
3671 if (stored_player[i].connected_network &&
3672 !stored_player[i].connected_locally)
3674 char *player_name = getNetworkPlayerName(i + 1);
3675 int player_width = xoffset_text + getTextWidth(player_name, font_nr);
3676 int xpos = SX + ALIGNED_XPOS(pos->x, player_width, pos->align);
3678 DrawNetworkPlayer(xpos, ypos, i, tile_size, border_size, font_nr);
3680 ypos += player_yoffset;
3685 void DrawNetworkPlayers(void)
3687 DrawNetworkPlayersExt(FALSE);
3690 void ClearNetworkPlayers(void)
3692 DrawNetworkPlayersExt(TRUE);
3695 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3696 int graphic, int sync_frame,
3699 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3701 if (mask_mode == USE_MASKING)
3702 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3704 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3707 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3708 int graphic, int sync_frame, int mask_mode)
3710 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3712 if (mask_mode == USE_MASKING)
3713 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3715 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3718 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3720 int lx = LEVELX(x), ly = LEVELY(y);
3722 if (!IN_SCR_FIELD(x, y))
3725 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3726 graphic, GfxFrame[lx][ly], NO_MASKING);
3728 MarkTileDirty(x, y);
3731 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3733 int lx = LEVELX(x), ly = LEVELY(y);
3735 if (!IN_SCR_FIELD(x, y))
3738 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3739 graphic, GfxFrame[lx][ly], NO_MASKING);
3740 MarkTileDirty(x, y);
3743 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3745 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3748 void DrawLevelElementAnimation(int x, int y, int element)
3750 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3752 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3755 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3757 int sx = SCREENX(x), sy = SCREENY(y);
3759 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3762 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3765 DrawGraphicAnimation(sx, sy, graphic);
3768 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3769 DrawLevelFieldCrumbled(x, y);
3771 if (GFX_CRUMBLED(Feld[x][y]))
3772 DrawLevelFieldCrumbled(x, y);
3776 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3778 int sx = SCREENX(x), sy = SCREENY(y);
3781 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3784 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3786 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3789 DrawGraphicAnimation(sx, sy, graphic);
3791 if (GFX_CRUMBLED(element))
3792 DrawLevelFieldCrumbled(x, y);
3795 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3797 if (player->use_murphy)
3799 /* this works only because currently only one player can be "murphy" ... */
3800 static int last_horizontal_dir = MV_LEFT;
3801 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3803 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3804 last_horizontal_dir = move_dir;
3806 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3808 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3810 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3816 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3819 static boolean equalGraphics(int graphic1, int graphic2)
3821 struct GraphicInfo *g1 = &graphic_info[graphic1];
3822 struct GraphicInfo *g2 = &graphic_info[graphic2];
3824 return (g1->bitmap == g2->bitmap &&
3825 g1->src_x == g2->src_x &&
3826 g1->src_y == g2->src_y &&
3827 g1->anim_frames == g2->anim_frames &&
3828 g1->anim_delay == g2->anim_delay &&
3829 g1->anim_mode == g2->anim_mode);
3832 void DrawAllPlayers(void)
3836 for (i = 0; i < MAX_PLAYERS; i++)
3837 if (stored_player[i].active)
3838 DrawPlayer(&stored_player[i]);
3841 void DrawPlayerField(int x, int y)
3843 if (!IS_PLAYER(x, y))
3846 DrawPlayer(PLAYERINFO(x, y));
3849 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3851 void DrawPlayer(struct PlayerInfo *player)
3853 int jx = player->jx;
3854 int jy = player->jy;
3855 int move_dir = player->MovDir;
3856 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3857 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3858 int last_jx = (player->is_moving ? jx - dx : jx);
3859 int last_jy = (player->is_moving ? jy - dy : jy);
3860 int next_jx = jx + dx;
3861 int next_jy = jy + dy;
3862 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3863 boolean player_is_opaque = FALSE;
3864 int sx = SCREENX(jx), sy = SCREENY(jy);
3865 int sxx = 0, syy = 0;
3866 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3868 int action = ACTION_DEFAULT;
3869 int last_player_graphic = getPlayerGraphic(player, move_dir);
3870 int last_player_frame = player->Frame;
3873 /* GfxElement[][] is set to the element the player is digging or collecting;
3874 remove also for off-screen player if the player is not moving anymore */
3875 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3876 GfxElement[jx][jy] = EL_UNDEFINED;
3878 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3882 if (!IN_LEV_FIELD(jx, jy))
3884 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3885 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3886 printf("DrawPlayerField(): This should never happen!\n");
3891 if (element == EL_EXPLOSION)
3894 action = (player->is_pushing ? ACTION_PUSHING :
3895 player->is_digging ? ACTION_DIGGING :
3896 player->is_collecting ? ACTION_COLLECTING :
3897 player->is_moving ? ACTION_MOVING :
3898 player->is_snapping ? ACTION_SNAPPING :
3899 player->is_dropping ? ACTION_DROPPING :
3900 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3902 if (player->is_waiting)
3903 move_dir = player->dir_waiting;
3905 InitPlayerGfxAnimation(player, action, move_dir);
3907 /* ----------------------------------------------------------------------- */
3908 /* draw things in the field the player is leaving, if needed */
3909 /* ----------------------------------------------------------------------- */
3911 if (player->is_moving)
3913 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3915 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3917 if (last_element == EL_DYNAMITE_ACTIVE ||
3918 last_element == EL_EM_DYNAMITE_ACTIVE ||
3919 last_element == EL_SP_DISK_RED_ACTIVE)
3920 DrawDynamite(last_jx, last_jy);
3922 DrawLevelFieldThruMask(last_jx, last_jy);
3924 else if (last_element == EL_DYNAMITE_ACTIVE ||
3925 last_element == EL_EM_DYNAMITE_ACTIVE ||
3926 last_element == EL_SP_DISK_RED_ACTIVE)
3927 DrawDynamite(last_jx, last_jy);
3929 /* !!! this is not enough to prevent flickering of players which are
3930 moving next to each others without a free tile between them -- this
3931 can only be solved by drawing all players layer by layer (first the
3932 background, then the foreground etc.) !!! => TODO */
3933 else if (!IS_PLAYER(last_jx, last_jy))
3934 DrawLevelField(last_jx, last_jy);
3937 DrawLevelField(last_jx, last_jy);
3940 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3941 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3944 if (!IN_SCR_FIELD(sx, sy))
3947 /* ----------------------------------------------------------------------- */
3948 /* draw things behind the player, if needed */
3949 /* ----------------------------------------------------------------------- */
3952 DrawLevelElement(jx, jy, Back[jx][jy]);
3953 else if (IS_ACTIVE_BOMB(element))
3954 DrawLevelElement(jx, jy, EL_EMPTY);
3957 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3959 int old_element = GfxElement[jx][jy];
3960 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3961 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3963 if (GFX_CRUMBLED(old_element))
3964 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3966 DrawGraphic(sx, sy, old_graphic, frame);
3968 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3969 player_is_opaque = TRUE;
3973 GfxElement[jx][jy] = EL_UNDEFINED;
3975 /* make sure that pushed elements are drawn with correct frame rate */
3976 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3978 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3979 GfxFrame[jx][jy] = player->StepFrame;
3981 DrawLevelField(jx, jy);
3985 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3986 /* ----------------------------------------------------------------------- */
3987 /* draw player himself */
3988 /* ----------------------------------------------------------------------- */
3990 graphic = getPlayerGraphic(player, move_dir);
3992 /* in the case of changed player action or direction, prevent the current
3993 animation frame from being restarted for identical animations */
3994 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3995 player->Frame = last_player_frame;
3997 frame = getGraphicAnimationFrame(graphic, player->Frame);
4001 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4002 sxx = player->GfxPos;
4004 syy = player->GfxPos;
4007 if (player_is_opaque)
4008 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4010 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4012 if (SHIELD_ON(player))
4014 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4015 IMG_SHIELD_NORMAL_ACTIVE);
4016 int frame = getGraphicAnimationFrame(graphic, -1);
4018 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4022 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4025 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4026 sxx = player->GfxPos;
4028 syy = player->GfxPos;
4032 /* ----------------------------------------------------------------------- */
4033 /* draw things the player is pushing, if needed */
4034 /* ----------------------------------------------------------------------- */
4036 if (player->is_pushing && player->is_moving)
4038 int px = SCREENX(jx), py = SCREENY(jy);
4039 int pxx = (TILEX - ABS(sxx)) * dx;
4040 int pyy = (TILEY - ABS(syy)) * dy;
4041 int gfx_frame = GfxFrame[jx][jy];
4047 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4049 element = Feld[next_jx][next_jy];
4050 gfx_frame = GfxFrame[next_jx][next_jy];
4053 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4055 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4056 frame = getGraphicAnimationFrame(graphic, sync_frame);
4058 /* draw background element under pushed element (like the Sokoban field) */
4059 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4061 /* this allows transparent pushing animation over non-black background */
4064 DrawLevelElement(jx, jy, Back[jx][jy]);
4066 DrawLevelElement(jx, jy, EL_EMPTY);
4068 if (Back[next_jx][next_jy])
4069 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4071 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4073 else if (Back[next_jx][next_jy])
4074 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4077 /* do not draw (EM style) pushing animation when pushing is finished */
4078 /* (two-tile animations usually do not contain start and end frame) */
4079 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4080 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4082 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4084 /* masked drawing is needed for EMC style (double) movement graphics */
4085 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4086 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4090 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4091 /* ----------------------------------------------------------------------- */
4092 /* draw player himself */
4093 /* ----------------------------------------------------------------------- */
4095 graphic = getPlayerGraphic(player, move_dir);
4097 /* in the case of changed player action or direction, prevent the current
4098 animation frame from being restarted for identical animations */
4099 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4100 player->Frame = last_player_frame;
4102 frame = getGraphicAnimationFrame(graphic, player->Frame);
4106 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4107 sxx = player->GfxPos;
4109 syy = player->GfxPos;
4112 if (player_is_opaque)
4113 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4115 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4117 if (SHIELD_ON(player))
4119 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4120 IMG_SHIELD_NORMAL_ACTIVE);
4121 int frame = getGraphicAnimationFrame(graphic, -1);
4123 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4127 /* ----------------------------------------------------------------------- */
4128 /* draw things in front of player (active dynamite or dynabombs) */
4129 /* ----------------------------------------------------------------------- */
4131 if (IS_ACTIVE_BOMB(element))
4133 graphic = el2img(element);
4134 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4136 if (game.emulation == EMU_SUPAPLEX)
4137 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4139 DrawGraphicThruMask(sx, sy, graphic, frame);
4142 if (player_is_moving && last_element == EL_EXPLOSION)
4144 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4145 GfxElement[last_jx][last_jy] : EL_EMPTY);
4146 int graphic = el_act2img(element, ACTION_EXPLODING);
4147 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4148 int phase = ExplodePhase[last_jx][last_jy] - 1;
4149 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4152 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4155 /* ----------------------------------------------------------------------- */
4156 /* draw elements the player is just walking/passing through/under */
4157 /* ----------------------------------------------------------------------- */
4159 if (player_is_moving)
4161 /* handle the field the player is leaving ... */
4162 if (IS_ACCESSIBLE_INSIDE(last_element))
4163 DrawLevelField(last_jx, last_jy);
4164 else if (IS_ACCESSIBLE_UNDER(last_element))
4165 DrawLevelFieldThruMask(last_jx, last_jy);
4168 /* do not redraw accessible elements if the player is just pushing them */
4169 if (!player_is_moving || !player->is_pushing)
4171 /* ... and the field the player is entering */
4172 if (IS_ACCESSIBLE_INSIDE(element))
4173 DrawLevelField(jx, jy);
4174 else if (IS_ACCESSIBLE_UNDER(element))
4175 DrawLevelFieldThruMask(jx, jy);
4178 MarkTileDirty(sx, sy);
4181 /* ------------------------------------------------------------------------- */
4183 void WaitForEventToContinue(void)
4185 boolean still_wait = TRUE;
4187 if (program.headless)
4190 /* simulate releasing mouse button over last gadget, if still pressed */
4192 HandleGadgets(-1, -1, 0);
4194 button_status = MB_RELEASED;
4202 if (NextValidEvent(&event))
4206 case EVENT_BUTTONRELEASE:
4207 case EVENT_KEYPRESS:
4208 #if defined(TARGET_SDL2)
4209 case SDL_CONTROLLERBUTTONDOWN:
4211 case SDL_JOYBUTTONDOWN:
4215 case EVENT_KEYRELEASE:
4216 ClearPlayerAction();
4220 HandleOtherEvents(&event);
4224 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4233 #define MAX_REQUEST_LINES 13
4234 #define MAX_REQUEST_LINE_FONT1_LEN 7
4235 #define MAX_REQUEST_LINE_FONT2_LEN 10
4237 static int RequestHandleEvents(unsigned int req_state)
4239 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
4240 local_player->LevelSolved_GameEnd);
4241 int width = request.width;
4242 int height = request.height;
4246 setRequestPosition(&sx, &sy, FALSE);
4248 button_status = MB_RELEASED;
4250 request_gadget_id = -1;
4257 /* the MM game engine does not use a special (scrollable) field buffer */
4258 if (level.game_engine_type != GAME_ENGINE_TYPE_MM)
4259 SetDrawtoField(DRAW_TO_FIELDBUFFER);
4261 HandleGameActions();
4263 SetDrawtoField(DRAW_TO_BACKBUFFER);
4265 if (global.use_envelope_request)
4267 /* copy current state of request area to middle of playfield area */
4268 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
4276 while (NextValidEvent(&event))
4280 case EVENT_BUTTONPRESS:
4281 case EVENT_BUTTONRELEASE:
4282 case EVENT_MOTIONNOTIFY:
4286 if (event.type == EVENT_MOTIONNOTIFY)
4291 motion_status = TRUE;
4292 mx = ((MotionEvent *) &event)->x;
4293 my = ((MotionEvent *) &event)->y;
4297 motion_status = FALSE;
4298 mx = ((ButtonEvent *) &event)->x;
4299 my = ((ButtonEvent *) &event)->y;
4300 if (event.type == EVENT_BUTTONPRESS)
4301 button_status = ((ButtonEvent *) &event)->button;
4303 button_status = MB_RELEASED;
4306 /* this sets 'request_gadget_id' */
4307 HandleGadgets(mx, my, button_status);
4309 switch (request_gadget_id)
4311 case TOOL_CTRL_ID_YES:
4314 case TOOL_CTRL_ID_NO:
4317 case TOOL_CTRL_ID_CONFIRM:
4318 result = TRUE | FALSE;
4321 case TOOL_CTRL_ID_PLAYER_1:
4324 case TOOL_CTRL_ID_PLAYER_2:
4327 case TOOL_CTRL_ID_PLAYER_3:
4330 case TOOL_CTRL_ID_PLAYER_4:
4341 #if defined(TARGET_SDL2)
4342 case SDL_WINDOWEVENT:
4343 HandleWindowEvent((WindowEvent *) &event);
4346 case SDL_APP_WILLENTERBACKGROUND:
4347 case SDL_APP_DIDENTERBACKGROUND:
4348 case SDL_APP_WILLENTERFOREGROUND:
4349 case SDL_APP_DIDENTERFOREGROUND:
4350 HandlePauseResumeEvent((PauseResumeEvent *) &event);
4354 case EVENT_KEYPRESS:
4356 Key key = GetEventKey((KeyEvent *)&event, TRUE);
4361 if (req_state & REQ_CONFIRM)
4367 #if defined(TARGET_SDL2)
4371 #if defined(KSYM_Rewind)
4372 case KSYM_Rewind: /* for Amazon Fire TV remote */
4380 #if defined(TARGET_SDL2)
4383 #if defined(KSYM_FastForward)
4384 case KSYM_FastForward: /* for Amazon Fire TV remote */
4391 HandleKeysDebug(key);
4395 if (req_state & REQ_PLAYER)
4397 int old_player_nr = setup.network_player_nr;
4400 result = old_player_nr + 1;
4405 result = old_player_nr + 1;
4436 case EVENT_KEYRELEASE:
4437 ClearPlayerAction();
4440 #if defined(TARGET_SDL2)
4441 case SDL_CONTROLLERBUTTONDOWN:
4442 switch (event.cbutton.button)
4444 case SDL_CONTROLLER_BUTTON_A:
4445 case SDL_CONTROLLER_BUTTON_X:
4446 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
4447 case SDL_CONTROLLER_BUTTON_LEFTSTICK:
4451 case SDL_CONTROLLER_BUTTON_B:
4452 case SDL_CONTROLLER_BUTTON_Y:
4453 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
4454 case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
4455 case SDL_CONTROLLER_BUTTON_BACK:
4460 if (req_state & REQ_PLAYER)
4462 int old_player_nr = setup.network_player_nr;
4465 result = old_player_nr + 1;
4467 switch (event.cbutton.button)
4469 case SDL_CONTROLLER_BUTTON_DPAD_UP:
4470 case SDL_CONTROLLER_BUTTON_Y:
4474 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
4475 case SDL_CONTROLLER_BUTTON_B:
4479 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
4480 case SDL_CONTROLLER_BUTTON_A:
4484 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
4485 case SDL_CONTROLLER_BUTTON_X:
4496 case SDL_CONTROLLERBUTTONUP:
4497 HandleJoystickEvent(&event);
4498 ClearPlayerAction();
4503 HandleOtherEvents(&event);
4508 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4510 int joy = AnyJoystick();
4512 if (joy & JOY_BUTTON_1)
4514 else if (joy & JOY_BUTTON_2)
4517 else if (AnyJoystick())
4519 int joy = AnyJoystick();
4521 if (req_state & REQ_PLAYER)
4525 else if (joy & JOY_RIGHT)
4527 else if (joy & JOY_DOWN)
4529 else if (joy & JOY_LEFT)
4536 if (global.use_envelope_request)
4538 /* copy back current state of pressed buttons inside request area */
4539 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4549 static boolean RequestDoor(char *text, unsigned int req_state)
4551 unsigned int old_door_state;
4552 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4553 int font_nr = FONT_TEXT_2;
4558 if (maxWordLengthInRequestString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4560 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4561 font_nr = FONT_TEXT_1;
4564 if (game_status == GAME_MODE_PLAYING)
4565 BlitScreenToBitmap(backbuffer);
4567 /* disable deactivated drawing when quick-loading level tape recording */
4568 if (tape.playing && tape.deactivate_display)
4569 TapeDeactivateDisplayOff(TRUE);
4571 SetMouseCursor(CURSOR_DEFAULT);
4573 /* pause network game while waiting for request to answer */
4574 if (network.enabled &&
4575 game_status == GAME_MODE_PLAYING &&
4577 req_state & REQUEST_WAIT_FOR_INPUT)
4578 SendToServer_PausePlaying();
4580 old_door_state = GetDoorState();
4582 /* simulate releasing mouse button over last gadget, if still pressed */
4584 HandleGadgets(-1, -1, 0);
4588 /* draw released gadget before proceeding */
4591 if (old_door_state & DOOR_OPEN_1)
4593 CloseDoor(DOOR_CLOSE_1);
4595 /* save old door content */
4596 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4597 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4600 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4601 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4603 /* clear door drawing field */
4604 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4606 /* force DOOR font inside door area */
4607 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4609 /* write text for request */
4610 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4612 char text_line[max_request_line_len + 1];
4618 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4620 tc = *(text_ptr + tx);
4621 // if (!tc || tc == ' ')
4622 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4626 if ((tc == '?' || tc == '!') && tl == 0)
4636 strncpy(text_line, text_ptr, tl);
4639 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4640 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4641 text_line, font_nr);
4643 text_ptr += tl + (tc == ' ' ? 1 : 0);
4644 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4649 if (req_state & REQ_ASK)
4651 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4652 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4654 else if (req_state & REQ_CONFIRM)
4656 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4658 else if (req_state & REQ_PLAYER)
4660 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4661 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4662 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4663 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4666 /* copy request gadgets to door backbuffer */
4667 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4669 OpenDoor(DOOR_OPEN_1);
4671 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4673 if (game_status == GAME_MODE_PLAYING)
4675 SetPanelBackground();
4676 SetDrawBackgroundMask(REDRAW_DOOR_1);
4680 SetDrawBackgroundMask(REDRAW_FIELD);
4686 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4688 // ---------- handle request buttons ----------
4689 result = RequestHandleEvents(req_state);
4693 if (!(req_state & REQ_STAY_OPEN))
4695 CloseDoor(DOOR_CLOSE_1);
4697 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4698 (req_state & REQ_REOPEN))
4699 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4704 if (game_status == GAME_MODE_PLAYING)
4706 SetPanelBackground();
4707 SetDrawBackgroundMask(REDRAW_DOOR_1);
4711 SetDrawBackgroundMask(REDRAW_FIELD);
4714 /* continue network game after request */
4715 if (network.enabled &&
4716 game_status == GAME_MODE_PLAYING &&
4718 req_state & REQUEST_WAIT_FOR_INPUT)
4719 SendToServer_ContinuePlaying();
4721 /* restore deactivated drawing when quick-loading level tape recording */
4722 if (tape.playing && tape.deactivate_display)
4723 TapeDeactivateDisplayOn();
4728 static boolean RequestEnvelope(char *text, unsigned int req_state)
4732 if (game_status == GAME_MODE_PLAYING)
4733 BlitScreenToBitmap(backbuffer);
4735 /* disable deactivated drawing when quick-loading level tape recording */
4736 if (tape.playing && tape.deactivate_display)
4737 TapeDeactivateDisplayOff(TRUE);
4739 SetMouseCursor(CURSOR_DEFAULT);
4741 /* pause network game while waiting for request to answer */
4742 if (network.enabled &&
4743 game_status == GAME_MODE_PLAYING &&
4745 req_state & REQUEST_WAIT_FOR_INPUT)
4746 SendToServer_PausePlaying();
4748 /* simulate releasing mouse button over last gadget, if still pressed */
4750 HandleGadgets(-1, -1, 0);
4754 // (replace with setting corresponding request background)
4755 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4756 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4758 /* clear door drawing field */
4759 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4761 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4763 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4765 if (game_status == GAME_MODE_PLAYING)
4767 SetPanelBackground();
4768 SetDrawBackgroundMask(REDRAW_DOOR_1);
4772 SetDrawBackgroundMask(REDRAW_FIELD);
4778 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4780 // ---------- handle request buttons ----------
4781 result = RequestHandleEvents(req_state);
4785 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4789 if (game_status == GAME_MODE_PLAYING)
4791 SetPanelBackground();
4792 SetDrawBackgroundMask(REDRAW_DOOR_1);
4796 SetDrawBackgroundMask(REDRAW_FIELD);
4799 /* continue network game after request */
4800 if (network.enabled &&
4801 game_status == GAME_MODE_PLAYING &&
4803 req_state & REQUEST_WAIT_FOR_INPUT)
4804 SendToServer_ContinuePlaying();
4806 /* restore deactivated drawing when quick-loading level tape recording */
4807 if (tape.playing && tape.deactivate_display)
4808 TapeDeactivateDisplayOn();
4813 boolean Request(char *text, unsigned int req_state)
4815 boolean overlay_active = GetOverlayActive();
4818 SetOverlayActive(FALSE);
4820 if (global.use_envelope_request)
4821 result = RequestEnvelope(text, req_state);
4823 result = RequestDoor(text, req_state);
4825 SetOverlayActive(overlay_active);
4830 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4832 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4833 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4836 if (dpo1->sort_priority != dpo2->sort_priority)
4837 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4839 compare_result = dpo1->nr - dpo2->nr;
4841 return compare_result;
4844 void InitGraphicCompatibilityInfo_Doors(void)
4850 struct DoorInfo *door;
4854 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4855 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4857 { -1, -1, -1, NULL }
4859 struct Rect door_rect_list[] =
4861 { DX, DY, DXSIZE, DYSIZE },
4862 { VX, VY, VXSIZE, VYSIZE }
4866 for (i = 0; doors[i].door_token != -1; i++)
4868 int door_token = doors[i].door_token;
4869 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4870 int part_1 = doors[i].part_1;
4871 int part_8 = doors[i].part_8;
4872 int part_2 = part_1 + 1;
4873 int part_3 = part_1 + 2;
4874 struct DoorInfo *door = doors[i].door;
4875 struct Rect *door_rect = &door_rect_list[door_index];
4876 boolean door_gfx_redefined = FALSE;
4878 /* check if any door part graphic definitions have been redefined */
4880 for (j = 0; door_part_controls[j].door_token != -1; j++)
4882 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4883 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4885 if (dpc->door_token == door_token && fi->redefined)
4886 door_gfx_redefined = TRUE;
4889 /* check for old-style door graphic/animation modifications */
4891 if (!door_gfx_redefined)
4893 if (door->anim_mode & ANIM_STATIC_PANEL)
4895 door->panel.step_xoffset = 0;
4896 door->panel.step_yoffset = 0;
4899 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4901 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4902 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4903 int num_door_steps, num_panel_steps;
4905 /* remove door part graphics other than the two default wings */
4907 for (j = 0; door_part_controls[j].door_token != -1; j++)
4909 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4910 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4912 if (dpc->graphic >= part_3 &&
4913 dpc->graphic <= part_8)
4917 /* set graphics and screen positions of the default wings */
4919 g_part_1->width = door_rect->width;
4920 g_part_1->height = door_rect->height;
4921 g_part_2->width = door_rect->width;
4922 g_part_2->height = door_rect->height;
4923 g_part_2->src_x = door_rect->width;
4924 g_part_2->src_y = g_part_1->src_y;
4926 door->part_2.x = door->part_1.x;
4927 door->part_2.y = door->part_1.y;
4929 if (door->width != -1)
4931 g_part_1->width = door->width;
4932 g_part_2->width = door->width;
4934 // special treatment for graphics and screen position of right wing
4935 g_part_2->src_x += door_rect->width - door->width;
4936 door->part_2.x += door_rect->width - door->width;
4939 if (door->height != -1)
4941 g_part_1->height = door->height;
4942 g_part_2->height = door->height;
4944 // special treatment for graphics and screen position of bottom wing
4945 g_part_2->src_y += door_rect->height - door->height;
4946 door->part_2.y += door_rect->height - door->height;
4949 /* set animation delays for the default wings and panels */
4951 door->part_1.step_delay = door->step_delay;
4952 door->part_2.step_delay = door->step_delay;
4953 door->panel.step_delay = door->step_delay;
4955 /* set animation draw order for the default wings */
4957 door->part_1.sort_priority = 2; /* draw left wing over ... */
4958 door->part_2.sort_priority = 1; /* ... right wing */
4960 /* set animation draw offset for the default wings */
4962 if (door->anim_mode & ANIM_HORIZONTAL)
4964 door->part_1.step_xoffset = door->step_offset;
4965 door->part_1.step_yoffset = 0;
4966 door->part_2.step_xoffset = door->step_offset * -1;
4967 door->part_2.step_yoffset = 0;
4969 num_door_steps = g_part_1->width / door->step_offset;
4971 else // ANIM_VERTICAL
4973 door->part_1.step_xoffset = 0;
4974 door->part_1.step_yoffset = door->step_offset;
4975 door->part_2.step_xoffset = 0;
4976 door->part_2.step_yoffset = door->step_offset * -1;
4978 num_door_steps = g_part_1->height / door->step_offset;
4981 /* set animation draw offset for the default panels */
4983 if (door->step_offset > 1)
4985 num_panel_steps = 2 * door_rect->height / door->step_offset;
4986 door->panel.start_step = num_panel_steps - num_door_steps;
4987 door->panel.start_step_closing = door->panel.start_step;
4991 num_panel_steps = door_rect->height / door->step_offset;
4992 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4993 door->panel.start_step_closing = door->panel.start_step;
4994 door->panel.step_delay *= 2;
5001 void InitDoors(void)
5005 for (i = 0; door_part_controls[i].door_token != -1; i++)
5007 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5008 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5010 /* initialize "start_step_opening" and "start_step_closing", if needed */
5011 if (dpc->pos->start_step_opening == 0 &&
5012 dpc->pos->start_step_closing == 0)
5014 // dpc->pos->start_step_opening = dpc->pos->start_step;
5015 dpc->pos->start_step_closing = dpc->pos->start_step;
5018 /* fill structure for door part draw order (sorted below) */
5020 dpo->sort_priority = dpc->pos->sort_priority;
5023 /* sort door part controls according to sort_priority and graphic number */
5024 qsort(door_part_order, MAX_DOOR_PARTS,
5025 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5028 unsigned int OpenDoor(unsigned int door_state)
5030 if (door_state & DOOR_COPY_BACK)
5032 if (door_state & DOOR_OPEN_1)
5033 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5034 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5036 if (door_state & DOOR_OPEN_2)
5037 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5038 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5040 door_state &= ~DOOR_COPY_BACK;
5043 return MoveDoor(door_state);
5046 unsigned int CloseDoor(unsigned int door_state)
5048 unsigned int old_door_state = GetDoorState();
5050 if (!(door_state & DOOR_NO_COPY_BACK))
5052 if (old_door_state & DOOR_OPEN_1)
5053 BlitBitmap(backbuffer, bitmap_db_door_1,
5054 DX, DY, DXSIZE, DYSIZE, 0, 0);
5056 if (old_door_state & DOOR_OPEN_2)
5057 BlitBitmap(backbuffer, bitmap_db_door_2,
5058 VX, VY, VXSIZE, VYSIZE, 0, 0);
5060 door_state &= ~DOOR_NO_COPY_BACK;
5063 return MoveDoor(door_state);
5066 unsigned int GetDoorState(void)
5068 return MoveDoor(DOOR_GET_STATE);
5071 unsigned int SetDoorState(unsigned int door_state)
5073 return MoveDoor(door_state | DOOR_SET_STATE);
5076 static int euclid(int a, int b)
5078 return (b ? euclid(b, a % b) : a);
5081 unsigned int MoveDoor(unsigned int door_state)
5083 struct Rect door_rect_list[] =
5085 { DX, DY, DXSIZE, DYSIZE },
5086 { VX, VY, VXSIZE, VYSIZE }
5088 static int door1 = DOOR_CLOSE_1;
5089 static int door2 = DOOR_CLOSE_2;
5090 unsigned int door_delay = 0;
5091 unsigned int door_delay_value;
5094 if (door_state == DOOR_GET_STATE)
5095 return (door1 | door2);
5097 if (door_state & DOOR_SET_STATE)
5099 if (door_state & DOOR_ACTION_1)
5100 door1 = door_state & DOOR_ACTION_1;
5101 if (door_state & DOOR_ACTION_2)
5102 door2 = door_state & DOOR_ACTION_2;
5104 return (door1 | door2);
5107 if (!(door_state & DOOR_FORCE_REDRAW))
5109 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5110 door_state &= ~DOOR_OPEN_1;
5111 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5112 door_state &= ~DOOR_CLOSE_1;
5113 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5114 door_state &= ~DOOR_OPEN_2;
5115 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5116 door_state &= ~DOOR_CLOSE_2;
5119 if (global.autoplay_leveldir)
5121 door_state |= DOOR_NO_DELAY;
5122 door_state &= ~DOOR_CLOSE_ALL;
5125 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
5126 door_state |= DOOR_NO_DELAY;
5128 if (door_state & DOOR_ACTION)
5130 boolean door_panel_drawn[NUM_DOORS];
5131 boolean panel_has_doors[NUM_DOORS];
5132 boolean door_part_skip[MAX_DOOR_PARTS];
5133 boolean door_part_done[MAX_DOOR_PARTS];
5134 boolean door_part_done_all;
5135 int num_steps[MAX_DOOR_PARTS];
5136 int max_move_delay = 0; // delay for complete animations of all doors
5137 int max_step_delay = 0; // delay (ms) between two animation frames
5138 int num_move_steps = 0; // number of animation steps for all doors
5139 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
5140 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
5141 int current_move_delay = 0;
5145 for (i = 0; i < NUM_DOORS; i++)
5146 panel_has_doors[i] = FALSE;
5148 for (i = 0; i < MAX_DOOR_PARTS; i++)
5150 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5151 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5152 int door_token = dpc->door_token;
5154 door_part_done[i] = FALSE;
5155 door_part_skip[i] = (!(door_state & door_token) ||
5159 for (i = 0; i < MAX_DOOR_PARTS; i++)
5161 int nr = door_part_order[i].nr;
5162 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5163 struct DoorPartPosInfo *pos = dpc->pos;
5164 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5165 int door_token = dpc->door_token;
5166 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5167 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5168 int step_xoffset = ABS(pos->step_xoffset);
5169 int step_yoffset = ABS(pos->step_yoffset);
5170 int step_delay = pos->step_delay;
5171 int current_door_state = door_state & door_token;
5172 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5173 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5174 boolean part_opening = (is_panel ? door_closing : door_opening);
5175 int start_step = (part_opening ? pos->start_step_opening :
5176 pos->start_step_closing);
5177 float move_xsize = (step_xoffset ? g->width : 0);
5178 float move_ysize = (step_yoffset ? g->height : 0);
5179 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5180 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5181 int move_steps = (move_xsteps && move_ysteps ?
5182 MIN(move_xsteps, move_ysteps) :
5183 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5184 int move_delay = move_steps * step_delay;
5186 if (door_part_skip[nr])
5189 max_move_delay = MAX(max_move_delay, move_delay);
5190 max_step_delay = (max_step_delay == 0 ? step_delay :
5191 euclid(max_step_delay, step_delay));
5192 num_steps[nr] = move_steps;
5196 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
5198 panel_has_doors[door_index] = TRUE;
5202 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
5204 num_move_steps = max_move_delay / max_step_delay;
5205 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
5207 door_delay_value = max_step_delay;
5209 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
5211 start = num_move_steps - 1;
5215 /* opening door sound has priority over simultaneously closing door */
5216 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5218 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5220 if (door_state & DOOR_OPEN_1)
5221 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
5222 if (door_state & DOOR_OPEN_2)
5223 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
5225 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5227 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5229 if (door_state & DOOR_CLOSE_1)
5230 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
5231 if (door_state & DOOR_CLOSE_2)
5232 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
5236 for (k = start; k < num_move_steps; k++)
5238 int last_frame = num_move_steps - 1; // last frame of this "for" loop
5240 door_part_done_all = TRUE;
5242 for (i = 0; i < NUM_DOORS; i++)
5243 door_panel_drawn[i] = FALSE;
5245 for (i = 0; i < MAX_DOOR_PARTS; i++)
5247 int nr = door_part_order[i].nr;
5248 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5249 struct DoorPartPosInfo *pos = dpc->pos;
5250 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5251 int door_token = dpc->door_token;
5252 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5253 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5254 boolean is_panel_and_door_has_closed = FALSE;
5255 struct Rect *door_rect = &door_rect_list[door_index];
5256 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5258 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5259 int current_door_state = door_state & door_token;
5260 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5261 boolean door_closing = !door_opening;
5262 boolean part_opening = (is_panel ? door_closing : door_opening);
5263 boolean part_closing = !part_opening;
5264 int start_step = (part_opening ? pos->start_step_opening :
5265 pos->start_step_closing);
5266 int step_delay = pos->step_delay;
5267 int step_factor = step_delay / max_step_delay;
5268 int k1 = (step_factor ? k / step_factor + 1 : k);
5269 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5270 int kk = MAX(0, k2);
5273 int src_x, src_y, src_xx, src_yy;
5274 int dst_x, dst_y, dst_xx, dst_yy;
5277 if (door_part_skip[nr])
5280 if (!(door_state & door_token))
5288 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
5289 int kk_door = MAX(0, k2_door);
5290 int sync_frame = kk_door * door_delay_value;
5291 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
5293 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
5294 &g_src_x, &g_src_y);
5299 if (!door_panel_drawn[door_index])
5301 ClearRectangle(drawto, door_rect->x, door_rect->y,
5302 door_rect->width, door_rect->height);
5304 door_panel_drawn[door_index] = TRUE;
5307 // draw opening or closing door parts
5309 if (pos->step_xoffset < 0) // door part on right side
5312 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5315 if (dst_xx + width > door_rect->width)
5316 width = door_rect->width - dst_xx;
5318 else // door part on left side
5321 dst_xx = pos->x - kk * pos->step_xoffset;
5325 src_xx = ABS(dst_xx);
5329 width = g->width - src_xx;
5331 if (width > door_rect->width)
5332 width = door_rect->width;
5334 // printf("::: k == %d [%d] \n", k, start_step);
5337 if (pos->step_yoffset < 0) // door part on bottom side
5340 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5343 if (dst_yy + height > door_rect->height)
5344 height = door_rect->height - dst_yy;
5346 else // door part on top side
5349 dst_yy = pos->y - kk * pos->step_yoffset;
5353 src_yy = ABS(dst_yy);
5357 height = g->height - src_yy;
5360 src_x = g_src_x + src_xx;
5361 src_y = g_src_y + src_yy;
5363 dst_x = door_rect->x + dst_xx;
5364 dst_y = door_rect->y + dst_yy;
5366 is_panel_and_door_has_closed =
5369 panel_has_doors[door_index] &&
5370 k >= num_move_steps_doors_only - 1);
5372 if (width >= 0 && width <= g->width &&
5373 height >= 0 && height <= g->height &&
5374 !is_panel_and_door_has_closed)
5376 if (is_panel || !pos->draw_masked)
5377 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5380 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5384 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5386 if ((part_opening && (width < 0 || height < 0)) ||
5387 (part_closing && (width >= g->width && height >= g->height)))
5388 door_part_done[nr] = TRUE;
5390 // continue door part animations, but not panel after door has closed
5391 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5392 door_part_done_all = FALSE;
5395 if (!(door_state & DOOR_NO_DELAY))
5399 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5401 current_move_delay += max_step_delay;
5403 /* prevent OS (Windows) from complaining about program not responding */
5407 if (door_part_done_all)
5411 if (!(door_state & DOOR_NO_DELAY))
5413 /* wait for specified door action post delay */
5414 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5415 door_delay_value = MAX(door_1.post_delay, door_2.post_delay);
5416 else if (door_state & DOOR_ACTION_1)
5417 door_delay_value = door_1.post_delay;
5418 else if (door_state & DOOR_ACTION_2)
5419 door_delay_value = door_2.post_delay;
5421 while (!DelayReached(&door_delay, door_delay_value))
5426 if (door_state & DOOR_ACTION_1)
5427 door1 = door_state & DOOR_ACTION_1;
5428 if (door_state & DOOR_ACTION_2)
5429 door2 = door_state & DOOR_ACTION_2;
5431 // draw masked border over door area
5432 DrawMaskedBorder(REDRAW_DOOR_1);
5433 DrawMaskedBorder(REDRAW_DOOR_2);
5435 ClearAutoRepeatKeyEvents();
5437 return (door1 | door2);
5440 static boolean useSpecialEditorDoor(void)
5442 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5443 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5445 // do not draw special editor door if editor border defined or redefined
5446 if (graphic_info[graphic].bitmap != NULL || redefined)
5449 // do not draw special editor door if global border defined to be empty
5450 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5453 // do not draw special editor door if viewport definitions do not match
5457 EY + EYSIZE != VY + VYSIZE)
5463 void DrawSpecialEditorDoor(void)
5465 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5466 int top_border_width = gfx1->width;
5467 int top_border_height = gfx1->height;
5468 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5469 int ex = EX - outer_border;
5470 int ey = EY - outer_border;
5471 int vy = VY - outer_border;
5472 int exsize = EXSIZE + 2 * outer_border;
5474 if (!useSpecialEditorDoor())
5477 /* draw bigger level editor toolbox window */
5478 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5479 top_border_width, top_border_height, ex, ey - top_border_height);
5480 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5481 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5483 redraw_mask |= REDRAW_ALL;
5486 void UndrawSpecialEditorDoor(void)
5488 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5489 int top_border_width = gfx1->width;
5490 int top_border_height = gfx1->height;
5491 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5492 int ex = EX - outer_border;
5493 int ey = EY - outer_border;
5494 int ey_top = ey - top_border_height;
5495 int exsize = EXSIZE + 2 * outer_border;
5496 int eysize = EYSIZE + 2 * outer_border;
5498 if (!useSpecialEditorDoor())
5501 /* draw normal tape recorder window */
5502 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5504 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5505 ex, ey_top, top_border_width, top_border_height,
5507 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5508 ex, ey, exsize, eysize, ex, ey);
5512 // if screen background is set to "[NONE]", clear editor toolbox window
5513 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5514 ClearRectangle(drawto, ex, ey, exsize, eysize);
5517 redraw_mask |= REDRAW_ALL;
5521 /* ---------- new tool button stuff ---------------------------------------- */
5526 struct TextPosInfo *pos;
5529 } toolbutton_info[NUM_TOOL_BUTTONS] =
5532 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5533 TOOL_CTRL_ID_YES, "yes"
5536 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5537 TOOL_CTRL_ID_NO, "no"
5540 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5541 TOOL_CTRL_ID_CONFIRM, "confirm"
5544 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5545 TOOL_CTRL_ID_PLAYER_1, "player 1"
5548 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5549 TOOL_CTRL_ID_PLAYER_2, "player 2"
5552 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5553 TOOL_CTRL_ID_PLAYER_3, "player 3"
5556 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5557 TOOL_CTRL_ID_PLAYER_4, "player 4"
5561 void CreateToolButtons(void)
5565 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5567 int graphic = toolbutton_info[i].graphic;
5568 struct GraphicInfo *gfx = &graphic_info[graphic];
5569 struct TextPosInfo *pos = toolbutton_info[i].pos;
5570 struct GadgetInfo *gi;
5571 Bitmap *deco_bitmap = None;
5572 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5573 unsigned int event_mask = GD_EVENT_RELEASED;
5576 int gd_x = gfx->src_x;
5577 int gd_y = gfx->src_y;
5578 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5579 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5584 if (global.use_envelope_request)
5586 setRequestPosition(&dx, &dy, TRUE);
5588 // check if request buttons are outside of envelope and fix, if needed
5589 if (x < 0 || x + gfx->width > request.width ||
5590 y < 0 || y + gfx->height > request.height)
5592 if (id == TOOL_CTRL_ID_YES)
5595 y = request.height - 2 * request.border_size - gfx->height;
5597 else if (id == TOOL_CTRL_ID_NO)
5599 x = request.width - 2 * request.border_size - gfx->width;
5600 y = request.height - 2 * request.border_size - gfx->height;
5602 else if (id == TOOL_CTRL_ID_CONFIRM)
5604 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5605 y = request.height - 2 * request.border_size - gfx->height;
5607 else if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5609 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5611 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5612 y = request.height - 2 * request.border_size - gfx->height * 2;
5614 x += (player_nr == 3 ? -1 : player_nr == 1 ? +1 : 0) * gfx->width;
5615 y += (player_nr == 0 ? -1 : player_nr == 2 ? +1 : 0) * gfx->height;
5620 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5622 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5624 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5625 pos->size, &deco_bitmap, &deco_x, &deco_y);
5626 deco_xpos = (gfx->width - pos->size) / 2;
5627 deco_ypos = (gfx->height - pos->size) / 2;
5630 gi = CreateGadget(GDI_CUSTOM_ID, id,
5631 GDI_IMAGE_ID, graphic,
5632 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5635 GDI_WIDTH, gfx->width,
5636 GDI_HEIGHT, gfx->height,
5637 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5638 GDI_STATE, GD_BUTTON_UNPRESSED,
5639 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5640 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5641 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5642 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5643 GDI_DECORATION_SIZE, pos->size, pos->size,
5644 GDI_DECORATION_SHIFTING, 1, 1,
5645 GDI_DIRECT_DRAW, FALSE,
5646 GDI_EVENT_MASK, event_mask,
5647 GDI_CALLBACK_ACTION, HandleToolButtons,
5651 Error(ERR_EXIT, "cannot create gadget");
5653 tool_gadget[id] = gi;
5657 void FreeToolButtons(void)
5661 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5662 FreeGadget(tool_gadget[i]);
5665 static void UnmapToolButtons(void)
5669 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5670 UnmapGadget(tool_gadget[i]);
5673 static void HandleToolButtons(struct GadgetInfo *gi)
5675 request_gadget_id = gi->custom_id;
5678 static struct Mapping_EM_to_RND_object
5681 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5682 boolean is_backside; /* backside of moving element */
5688 em_object_mapping_list[] =
5691 Xblank, TRUE, FALSE,
5695 Yacid_splash_eB, FALSE, FALSE,
5696 EL_ACID_SPLASH_RIGHT, -1, -1
5699 Yacid_splash_wB, FALSE, FALSE,
5700 EL_ACID_SPLASH_LEFT, -1, -1
5703 #ifdef EM_ENGINE_BAD_ROLL
5705 Xstone_force_e, FALSE, FALSE,
5706 EL_ROCK, -1, MV_BIT_RIGHT
5709 Xstone_force_w, FALSE, FALSE,
5710 EL_ROCK, -1, MV_BIT_LEFT
5713 Xnut_force_e, FALSE, FALSE,
5714 EL_NUT, -1, MV_BIT_RIGHT
5717 Xnut_force_w, FALSE, FALSE,
5718 EL_NUT, -1, MV_BIT_LEFT
5721 Xspring_force_e, FALSE, FALSE,
5722 EL_SPRING, -1, MV_BIT_RIGHT
5725 Xspring_force_w, FALSE, FALSE,
5726 EL_SPRING, -1, MV_BIT_LEFT
5729 Xemerald_force_e, FALSE, FALSE,
5730 EL_EMERALD, -1, MV_BIT_RIGHT
5733 Xemerald_force_w, FALSE, FALSE,
5734 EL_EMERALD, -1, MV_BIT_LEFT
5737 Xdiamond_force_e, FALSE, FALSE,
5738 EL_DIAMOND, -1, MV_BIT_RIGHT
5741 Xdiamond_force_w, FALSE, FALSE,
5742 EL_DIAMOND, -1, MV_BIT_LEFT
5745 Xbomb_force_e, FALSE, FALSE,
5746 EL_BOMB, -1, MV_BIT_RIGHT
5749 Xbomb_force_w, FALSE, FALSE,
5750 EL_BOMB, -1, MV_BIT_LEFT
5752 #endif /* EM_ENGINE_BAD_ROLL */
5755 Xstone, TRUE, FALSE,
5759 Xstone_pause, FALSE, FALSE,
5763 Xstone_fall, FALSE, FALSE,
5767 Ystone_s, FALSE, FALSE,
5768 EL_ROCK, ACTION_FALLING, -1
5771 Ystone_sB, FALSE, TRUE,
5772 EL_ROCK, ACTION_FALLING, -1
5775 Ystone_e, FALSE, FALSE,
5776 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5779 Ystone_eB, FALSE, TRUE,
5780 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5783 Ystone_w, FALSE, FALSE,
5784 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5787 Ystone_wB, FALSE, TRUE,
5788 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5795 Xnut_pause, FALSE, FALSE,
5799 Xnut_fall, FALSE, FALSE,
5803 Ynut_s, FALSE, FALSE,
5804 EL_NUT, ACTION_FALLING, -1
5807 Ynut_sB, FALSE, TRUE,
5808 EL_NUT, ACTION_FALLING, -1
5811 Ynut_e, FALSE, FALSE,
5812 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5815 Ynut_eB, FALSE, TRUE,
5816 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5819 Ynut_w, FALSE, FALSE,
5820 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5823 Ynut_wB, FALSE, TRUE,
5824 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5827 Xbug_n, TRUE, FALSE,
5831 Xbug_e, TRUE, FALSE,
5832 EL_BUG_RIGHT, -1, -1
5835 Xbug_s, TRUE, FALSE,
5839 Xbug_w, TRUE, FALSE,
5843 Xbug_gon, FALSE, FALSE,
5847 Xbug_goe, FALSE, FALSE,
5848 EL_BUG_RIGHT, -1, -1
5851 Xbug_gos, FALSE, FALSE,
5855 Xbug_gow, FALSE, FALSE,
5859 Ybug_n, FALSE, FALSE,
5860 EL_BUG, ACTION_MOVING, MV_BIT_UP
5863 Ybug_nB, FALSE, TRUE,
5864 EL_BUG, ACTION_MOVING, MV_BIT_UP
5867 Ybug_e, FALSE, FALSE,
5868 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5871 Ybug_eB, FALSE, TRUE,
5872 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5875 Ybug_s, FALSE, FALSE,
5876 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5879 Ybug_sB, FALSE, TRUE,
5880 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5883 Ybug_w, FALSE, FALSE,
5884 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5887 Ybug_wB, FALSE, TRUE,
5888 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5891 Ybug_w_n, FALSE, FALSE,
5892 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5895 Ybug_n_e, FALSE, FALSE,
5896 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5899 Ybug_e_s, FALSE, FALSE,
5900 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5903 Ybug_s_w, FALSE, FALSE,
5904 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5907 Ybug_e_n, FALSE, FALSE,
5908 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5911 Ybug_s_e, FALSE, FALSE,
5912 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5915 Ybug_w_s, FALSE, FALSE,
5916 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5919 Ybug_n_w, FALSE, FALSE,
5920 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5923 Ybug_stone, FALSE, FALSE,
5924 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5927 Ybug_spring, FALSE, FALSE,
5928 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5931 Xtank_n, TRUE, FALSE,
5932 EL_SPACESHIP_UP, -1, -1
5935 Xtank_e, TRUE, FALSE,
5936 EL_SPACESHIP_RIGHT, -1, -1
5939 Xtank_s, TRUE, FALSE,
5940 EL_SPACESHIP_DOWN, -1, -1
5943 Xtank_w, TRUE, FALSE,
5944 EL_SPACESHIP_LEFT, -1, -1
5947 Xtank_gon, FALSE, FALSE,
5948 EL_SPACESHIP_UP, -1, -1
5951 Xtank_goe, FALSE, FALSE,
5952 EL_SPACESHIP_RIGHT, -1, -1
5955 Xtank_gos, FALSE, FALSE,
5956 EL_SPACESHIP_DOWN, -1, -1
5959 Xtank_gow, FALSE, FALSE,
5960 EL_SPACESHIP_LEFT, -1, -1
5963 Ytank_n, FALSE, FALSE,
5964 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5967 Ytank_nB, FALSE, TRUE,
5968 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5971 Ytank_e, FALSE, FALSE,
5972 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5975 Ytank_eB, FALSE, TRUE,
5976 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5979 Ytank_s, FALSE, FALSE,
5980 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5983 Ytank_sB, FALSE, TRUE,
5984 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5987 Ytank_w, FALSE, FALSE,
5988 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5991 Ytank_wB, FALSE, TRUE,
5992 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5995 Ytank_w_n, FALSE, FALSE,
5996 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5999 Ytank_n_e, FALSE, FALSE,
6000 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6003 Ytank_e_s, FALSE, FALSE,
6004 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6007 Ytank_s_w, FALSE, FALSE,
6008 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6011 Ytank_e_n, FALSE, FALSE,
6012 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6015 Ytank_s_e, FALSE, FALSE,
6016 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6019 Ytank_w_s, FALSE, FALSE,
6020 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6023 Ytank_n_w, FALSE, FALSE,
6024 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6027 Ytank_stone, FALSE, FALSE,
6028 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
6031 Ytank_spring, FALSE, FALSE,
6032 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
6035 Xandroid, TRUE, FALSE,
6036 EL_EMC_ANDROID, ACTION_ACTIVE, -1
6039 Xandroid_1_n, FALSE, FALSE,
6040 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
6043 Xandroid_2_n, FALSE, FALSE,
6044 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
6047 Xandroid_1_e, FALSE, FALSE,
6048 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
6051 Xandroid_2_e, FALSE, FALSE,
6052 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
6055 Xandroid_1_w, FALSE, FALSE,
6056 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
6059 Xandroid_2_w, FALSE, FALSE,
6060 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
6063 Xandroid_1_s, FALSE, FALSE,
6064 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
6067 Xandroid_2_s, FALSE, FALSE,
6068 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
6071 Yandroid_n, FALSE, FALSE,
6072 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
6075 Yandroid_nB, FALSE, TRUE,
6076 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
6079 Yandroid_ne, FALSE, FALSE,
6080 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
6083 Yandroid_neB, FALSE, TRUE,
6084 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
6087 Yandroid_e, FALSE, FALSE,
6088 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
6091 Yandroid_eB, FALSE, TRUE,
6092 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
6095 Yandroid_se, FALSE, FALSE,
6096 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
6099 Yandroid_seB, FALSE, TRUE,
6100 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
6103 Yandroid_s, FALSE, FALSE,
6104 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6107 Yandroid_sB, FALSE, TRUE,
6108 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6111 Yandroid_sw, FALSE, FALSE,
6112 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
6115 Yandroid_swB, FALSE, TRUE,
6116 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
6119 Yandroid_w, FALSE, FALSE,
6120 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6123 Yandroid_wB, FALSE, TRUE,
6124 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6127 Yandroid_nw, FALSE, FALSE,
6128 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
6131 Yandroid_nwB, FALSE, TRUE,
6132 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
6135 Xspring, TRUE, FALSE,
6139 Xspring_pause, FALSE, FALSE,
6143 Xspring_e, FALSE, FALSE,
6147 Xspring_w, FALSE, FALSE,
6151 Xspring_fall, FALSE, FALSE,
6155 Yspring_s, FALSE, FALSE,
6156 EL_SPRING, ACTION_FALLING, -1
6159 Yspring_sB, FALSE, TRUE,
6160 EL_SPRING, ACTION_FALLING, -1
6163 Yspring_e, FALSE, FALSE,
6164 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6167 Yspring_eB, FALSE, TRUE,
6168 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6171 Yspring_w, FALSE, FALSE,
6172 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6175 Yspring_wB, FALSE, TRUE,
6176 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6179 Yspring_kill_e, FALSE, FALSE,
6180 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6183 Yspring_kill_eB, FALSE, TRUE,
6184 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6187 Yspring_kill_w, FALSE, FALSE,
6188 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6191 Yspring_kill_wB, FALSE, TRUE,
6192 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6195 Xeater_n, TRUE, FALSE,
6196 EL_YAMYAM_UP, -1, -1
6199 Xeater_e, TRUE, FALSE,
6200 EL_YAMYAM_RIGHT, -1, -1
6203 Xeater_w, TRUE, FALSE,
6204 EL_YAMYAM_LEFT, -1, -1
6207 Xeater_s, TRUE, FALSE,
6208 EL_YAMYAM_DOWN, -1, -1
6211 Yeater_n, FALSE, FALSE,
6212 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6215 Yeater_nB, FALSE, TRUE,
6216 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6219 Yeater_e, FALSE, FALSE,
6220 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6223 Yeater_eB, FALSE, TRUE,
6224 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6227 Yeater_s, FALSE, FALSE,
6228 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6231 Yeater_sB, FALSE, TRUE,
6232 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6235 Yeater_w, FALSE, FALSE,
6236 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6239 Yeater_wB, FALSE, TRUE,
6240 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6243 Yeater_stone, FALSE, FALSE,
6244 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
6247 Yeater_spring, FALSE, FALSE,
6248 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
6251 Xalien, TRUE, FALSE,
6255 Xalien_pause, FALSE, FALSE,
6259 Yalien_n, FALSE, FALSE,
6260 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6263 Yalien_nB, FALSE, TRUE,
6264 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6267 Yalien_e, FALSE, FALSE,
6268 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6271 Yalien_eB, FALSE, TRUE,
6272 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6275 Yalien_s, FALSE, FALSE,
6276 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6279 Yalien_sB, FALSE, TRUE,
6280 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6283 Yalien_w, FALSE, FALSE,
6284 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6287 Yalien_wB, FALSE, TRUE,
6288 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6291 Yalien_stone, FALSE, FALSE,
6292 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
6295 Yalien_spring, FALSE, FALSE,
6296 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
6299 Xemerald, TRUE, FALSE,
6303 Xemerald_pause, FALSE, FALSE,
6307 Xemerald_fall, FALSE, FALSE,
6311 Xemerald_shine, FALSE, FALSE,
6312 EL_EMERALD, ACTION_TWINKLING, -1
6315 Yemerald_s, FALSE, FALSE,
6316 EL_EMERALD, ACTION_FALLING, -1
6319 Yemerald_sB, FALSE, TRUE,
6320 EL_EMERALD, ACTION_FALLING, -1
6323 Yemerald_e, FALSE, FALSE,
6324 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6327 Yemerald_eB, FALSE, TRUE,
6328 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6331 Yemerald_w, FALSE, FALSE,
6332 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6335 Yemerald_wB, FALSE, TRUE,
6336 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6339 Yemerald_eat, FALSE, FALSE,
6340 EL_EMERALD, ACTION_COLLECTING, -1
6343 Yemerald_stone, FALSE, FALSE,
6344 EL_NUT, ACTION_BREAKING, -1
6347 Xdiamond, TRUE, FALSE,
6351 Xdiamond_pause, FALSE, FALSE,
6355 Xdiamond_fall, FALSE, FALSE,
6359 Xdiamond_shine, FALSE, FALSE,
6360 EL_DIAMOND, ACTION_TWINKLING, -1
6363 Ydiamond_s, FALSE, FALSE,
6364 EL_DIAMOND, ACTION_FALLING, -1
6367 Ydiamond_sB, FALSE, TRUE,
6368 EL_DIAMOND, ACTION_FALLING, -1
6371 Ydiamond_e, FALSE, FALSE,
6372 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6375 Ydiamond_eB, FALSE, TRUE,
6376 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6379 Ydiamond_w, FALSE, FALSE,
6380 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6383 Ydiamond_wB, FALSE, TRUE,
6384 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6387 Ydiamond_eat, FALSE, FALSE,
6388 EL_DIAMOND, ACTION_COLLECTING, -1
6391 Ydiamond_stone, FALSE, FALSE,
6392 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6395 Xdrip_fall, TRUE, FALSE,
6396 EL_AMOEBA_DROP, -1, -1
6399 Xdrip_stretch, FALSE, FALSE,
6400 EL_AMOEBA_DROP, ACTION_FALLING, -1
6403 Xdrip_stretchB, FALSE, TRUE,
6404 EL_AMOEBA_DROP, ACTION_FALLING, -1
6407 Xdrip_eat, FALSE, FALSE,
6408 EL_AMOEBA_DROP, ACTION_GROWING, -1
6411 Ydrip_s1, FALSE, FALSE,
6412 EL_AMOEBA_DROP, ACTION_FALLING, -1
6415 Ydrip_s1B, FALSE, TRUE,
6416 EL_AMOEBA_DROP, ACTION_FALLING, -1
6419 Ydrip_s2, FALSE, FALSE,
6420 EL_AMOEBA_DROP, ACTION_FALLING, -1
6423 Ydrip_s2B, FALSE, TRUE,
6424 EL_AMOEBA_DROP, ACTION_FALLING, -1
6431 Xbomb_pause, FALSE, FALSE,
6435 Xbomb_fall, FALSE, FALSE,
6439 Ybomb_s, FALSE, FALSE,
6440 EL_BOMB, ACTION_FALLING, -1
6443 Ybomb_sB, FALSE, TRUE,
6444 EL_BOMB, ACTION_FALLING, -1
6447 Ybomb_e, FALSE, FALSE,
6448 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6451 Ybomb_eB, FALSE, TRUE,
6452 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6455 Ybomb_w, FALSE, FALSE,
6456 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6459 Ybomb_wB, FALSE, TRUE,
6460 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6463 Ybomb_eat, FALSE, FALSE,
6464 EL_BOMB, ACTION_ACTIVATING, -1
6467 Xballoon, TRUE, FALSE,
6471 Yballoon_n, FALSE, FALSE,
6472 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6475 Yballoon_nB, FALSE, TRUE,
6476 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6479 Yballoon_e, FALSE, FALSE,
6480 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6483 Yballoon_eB, FALSE, TRUE,
6484 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6487 Yballoon_s, FALSE, FALSE,
6488 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6491 Yballoon_sB, FALSE, TRUE,
6492 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6495 Yballoon_w, FALSE, FALSE,
6496 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6499 Yballoon_wB, FALSE, TRUE,
6500 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6503 Xgrass, TRUE, FALSE,
6504 EL_EMC_GRASS, -1, -1
6507 Ygrass_nB, FALSE, FALSE,
6508 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6511 Ygrass_eB, FALSE, FALSE,
6512 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6515 Ygrass_sB, FALSE, FALSE,
6516 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6519 Ygrass_wB, FALSE, FALSE,
6520 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6527 Ydirt_nB, FALSE, FALSE,
6528 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6531 Ydirt_eB, FALSE, FALSE,
6532 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6535 Ydirt_sB, FALSE, FALSE,
6536 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6539 Ydirt_wB, FALSE, FALSE,
6540 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6543 Xacid_ne, TRUE, FALSE,
6544 EL_ACID_POOL_TOPRIGHT, -1, -1
6547 Xacid_se, TRUE, FALSE,
6548 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6551 Xacid_s, TRUE, FALSE,
6552 EL_ACID_POOL_BOTTOM, -1, -1
6555 Xacid_sw, TRUE, FALSE,
6556 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6559 Xacid_nw, TRUE, FALSE,
6560 EL_ACID_POOL_TOPLEFT, -1, -1
6563 Xacid_1, TRUE, FALSE,
6567 Xacid_2, FALSE, FALSE,
6571 Xacid_3, FALSE, FALSE,
6575 Xacid_4, FALSE, FALSE,
6579 Xacid_5, FALSE, FALSE,
6583 Xacid_6, FALSE, FALSE,
6587 Xacid_7, FALSE, FALSE,
6591 Xacid_8, FALSE, FALSE,
6595 Xball_1, TRUE, FALSE,
6596 EL_EMC_MAGIC_BALL, -1, -1
6599 Xball_1B, FALSE, FALSE,
6600 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6603 Xball_2, FALSE, FALSE,
6604 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6607 Xball_2B, FALSE, FALSE,
6608 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6611 Yball_eat, FALSE, FALSE,
6612 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6615 Ykey_1_eat, FALSE, FALSE,
6616 EL_EM_KEY_1, ACTION_COLLECTING, -1
6619 Ykey_2_eat, FALSE, FALSE,
6620 EL_EM_KEY_2, ACTION_COLLECTING, -1
6623 Ykey_3_eat, FALSE, FALSE,
6624 EL_EM_KEY_3, ACTION_COLLECTING, -1
6627 Ykey_4_eat, FALSE, FALSE,
6628 EL_EM_KEY_4, ACTION_COLLECTING, -1
6631 Ykey_5_eat, FALSE, FALSE,
6632 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6635 Ykey_6_eat, FALSE, FALSE,
6636 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6639 Ykey_7_eat, FALSE, FALSE,
6640 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6643 Ykey_8_eat, FALSE, FALSE,
6644 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6647 Ylenses_eat, FALSE, FALSE,
6648 EL_EMC_LENSES, ACTION_COLLECTING, -1
6651 Ymagnify_eat, FALSE, FALSE,
6652 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6655 Ygrass_eat, FALSE, FALSE,
6656 EL_EMC_GRASS, ACTION_SNAPPING, -1
6659 Ydirt_eat, FALSE, FALSE,
6660 EL_SAND, ACTION_SNAPPING, -1
6663 Xgrow_ns, TRUE, FALSE,
6664 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6667 Ygrow_ns_eat, FALSE, FALSE,
6668 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6671 Xgrow_ew, TRUE, FALSE,
6672 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6675 Ygrow_ew_eat, FALSE, FALSE,
6676 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6679 Xwonderwall, TRUE, FALSE,
6680 EL_MAGIC_WALL, -1, -1
6683 XwonderwallB, FALSE, FALSE,
6684 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6687 Xamoeba_1, TRUE, FALSE,
6688 EL_AMOEBA_DRY, ACTION_OTHER, -1
6691 Xamoeba_2, FALSE, FALSE,
6692 EL_AMOEBA_DRY, ACTION_OTHER, -1
6695 Xamoeba_3, FALSE, FALSE,
6696 EL_AMOEBA_DRY, ACTION_OTHER, -1
6699 Xamoeba_4, FALSE, FALSE,
6700 EL_AMOEBA_DRY, ACTION_OTHER, -1
6703 Xamoeba_5, TRUE, FALSE,
6704 EL_AMOEBA_WET, ACTION_OTHER, -1
6707 Xamoeba_6, FALSE, FALSE,
6708 EL_AMOEBA_WET, ACTION_OTHER, -1
6711 Xamoeba_7, FALSE, FALSE,
6712 EL_AMOEBA_WET, ACTION_OTHER, -1
6715 Xamoeba_8, FALSE, FALSE,
6716 EL_AMOEBA_WET, ACTION_OTHER, -1
6719 Xdoor_1, TRUE, FALSE,
6720 EL_EM_GATE_1, -1, -1
6723 Xdoor_2, TRUE, FALSE,
6724 EL_EM_GATE_2, -1, -1
6727 Xdoor_3, TRUE, FALSE,
6728 EL_EM_GATE_3, -1, -1
6731 Xdoor_4, TRUE, FALSE,
6732 EL_EM_GATE_4, -1, -1
6735 Xdoor_5, TRUE, FALSE,
6736 EL_EMC_GATE_5, -1, -1
6739 Xdoor_6, TRUE, FALSE,
6740 EL_EMC_GATE_6, -1, -1
6743 Xdoor_7, TRUE, FALSE,
6744 EL_EMC_GATE_7, -1, -1
6747 Xdoor_8, TRUE, FALSE,
6748 EL_EMC_GATE_8, -1, -1
6751 Xkey_1, TRUE, FALSE,
6755 Xkey_2, TRUE, FALSE,
6759 Xkey_3, TRUE, FALSE,
6763 Xkey_4, TRUE, FALSE,
6767 Xkey_5, TRUE, FALSE,
6768 EL_EMC_KEY_5, -1, -1
6771 Xkey_6, TRUE, FALSE,
6772 EL_EMC_KEY_6, -1, -1
6775 Xkey_7, TRUE, FALSE,
6776 EL_EMC_KEY_7, -1, -1
6779 Xkey_8, TRUE, FALSE,
6780 EL_EMC_KEY_8, -1, -1
6783 Xwind_n, TRUE, FALSE,
6784 EL_BALLOON_SWITCH_UP, -1, -1
6787 Xwind_e, TRUE, FALSE,
6788 EL_BALLOON_SWITCH_RIGHT, -1, -1
6791 Xwind_s, TRUE, FALSE,
6792 EL_BALLOON_SWITCH_DOWN, -1, -1
6795 Xwind_w, TRUE, FALSE,
6796 EL_BALLOON_SWITCH_LEFT, -1, -1
6799 Xwind_nesw, TRUE, FALSE,
6800 EL_BALLOON_SWITCH_ANY, -1, -1
6803 Xwind_stop, TRUE, FALSE,
6804 EL_BALLOON_SWITCH_NONE, -1, -1
6808 EL_EM_EXIT_CLOSED, -1, -1
6811 Xexit_1, TRUE, FALSE,
6812 EL_EM_EXIT_OPEN, -1, -1
6815 Xexit_2, FALSE, FALSE,
6816 EL_EM_EXIT_OPEN, -1, -1
6819 Xexit_3, FALSE, FALSE,
6820 EL_EM_EXIT_OPEN, -1, -1
6823 Xdynamite, TRUE, FALSE,
6824 EL_EM_DYNAMITE, -1, -1
6827 Ydynamite_eat, FALSE, FALSE,
6828 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6831 Xdynamite_1, TRUE, FALSE,
6832 EL_EM_DYNAMITE_ACTIVE, -1, -1
6835 Xdynamite_2, FALSE, FALSE,
6836 EL_EM_DYNAMITE_ACTIVE, -1, -1
6839 Xdynamite_3, FALSE, FALSE,
6840 EL_EM_DYNAMITE_ACTIVE, -1, -1
6843 Xdynamite_4, FALSE, FALSE,
6844 EL_EM_DYNAMITE_ACTIVE, -1, -1
6847 Xbumper, TRUE, FALSE,
6848 EL_EMC_SPRING_BUMPER, -1, -1
6851 XbumperB, FALSE, FALSE,
6852 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6855 Xwheel, TRUE, FALSE,
6856 EL_ROBOT_WHEEL, -1, -1
6859 XwheelB, FALSE, FALSE,
6860 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6863 Xswitch, TRUE, FALSE,
6864 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6867 XswitchB, FALSE, FALSE,
6868 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6872 EL_QUICKSAND_EMPTY, -1, -1
6875 Xsand_stone, TRUE, FALSE,
6876 EL_QUICKSAND_FULL, -1, -1
6879 Xsand_stonein_1, FALSE, TRUE,
6880 EL_ROCK, ACTION_FILLING, -1
6883 Xsand_stonein_2, FALSE, TRUE,
6884 EL_ROCK, ACTION_FILLING, -1
6887 Xsand_stonein_3, FALSE, TRUE,
6888 EL_ROCK, ACTION_FILLING, -1
6891 Xsand_stonein_4, FALSE, TRUE,
6892 EL_ROCK, ACTION_FILLING, -1
6895 Xsand_stonesand_1, FALSE, FALSE,
6896 EL_QUICKSAND_EMPTYING, -1, -1
6899 Xsand_stonesand_2, FALSE, FALSE,
6900 EL_QUICKSAND_EMPTYING, -1, -1
6903 Xsand_stonesand_3, FALSE, FALSE,
6904 EL_QUICKSAND_EMPTYING, -1, -1
6907 Xsand_stonesand_4, FALSE, FALSE,
6908 EL_QUICKSAND_EMPTYING, -1, -1
6911 Xsand_stonesand_quickout_1, FALSE, FALSE,
6912 EL_QUICKSAND_EMPTYING, -1, -1
6915 Xsand_stonesand_quickout_2, FALSE, FALSE,
6916 EL_QUICKSAND_EMPTYING, -1, -1
6919 Xsand_stoneout_1, FALSE, FALSE,
6920 EL_ROCK, ACTION_EMPTYING, -1
6923 Xsand_stoneout_2, FALSE, FALSE,
6924 EL_ROCK, ACTION_EMPTYING, -1
6927 Xsand_sandstone_1, FALSE, FALSE,
6928 EL_QUICKSAND_FILLING, -1, -1
6931 Xsand_sandstone_2, FALSE, FALSE,
6932 EL_QUICKSAND_FILLING, -1, -1
6935 Xsand_sandstone_3, FALSE, FALSE,
6936 EL_QUICKSAND_FILLING, -1, -1
6939 Xsand_sandstone_4, FALSE, FALSE,
6940 EL_QUICKSAND_FILLING, -1, -1
6943 Xplant, TRUE, FALSE,
6944 EL_EMC_PLANT, -1, -1
6947 Yplant, FALSE, FALSE,
6948 EL_EMC_PLANT, -1, -1
6951 Xlenses, TRUE, FALSE,
6952 EL_EMC_LENSES, -1, -1
6955 Xmagnify, TRUE, FALSE,
6956 EL_EMC_MAGNIFIER, -1, -1
6959 Xdripper, TRUE, FALSE,
6960 EL_EMC_DRIPPER, -1, -1
6963 XdripperB, FALSE, FALSE,
6964 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6967 Xfake_blank, TRUE, FALSE,
6968 EL_INVISIBLE_WALL, -1, -1
6971 Xfake_blankB, FALSE, FALSE,
6972 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6975 Xfake_grass, TRUE, FALSE,
6976 EL_EMC_FAKE_GRASS, -1, -1
6979 Xfake_grassB, FALSE, FALSE,
6980 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6983 Xfake_door_1, TRUE, FALSE,
6984 EL_EM_GATE_1_GRAY, -1, -1
6987 Xfake_door_2, TRUE, FALSE,
6988 EL_EM_GATE_2_GRAY, -1, -1
6991 Xfake_door_3, TRUE, FALSE,
6992 EL_EM_GATE_3_GRAY, -1, -1
6995 Xfake_door_4, TRUE, FALSE,
6996 EL_EM_GATE_4_GRAY, -1, -1
6999 Xfake_door_5, TRUE, FALSE,
7000 EL_EMC_GATE_5_GRAY, -1, -1
7003 Xfake_door_6, TRUE, FALSE,
7004 EL_EMC_GATE_6_GRAY, -1, -1
7007 Xfake_door_7, TRUE, FALSE,
7008 EL_EMC_GATE_7_GRAY, -1, -1
7011 Xfake_door_8, TRUE, FALSE,
7012 EL_EMC_GATE_8_GRAY, -1, -1
7015 Xfake_acid_1, TRUE, FALSE,
7016 EL_EMC_FAKE_ACID, -1, -1
7019 Xfake_acid_2, FALSE, FALSE,
7020 EL_EMC_FAKE_ACID, -1, -1
7023 Xfake_acid_3, FALSE, FALSE,
7024 EL_EMC_FAKE_ACID, -1, -1
7027 Xfake_acid_4, FALSE, FALSE,
7028 EL_EMC_FAKE_ACID, -1, -1
7031 Xfake_acid_5, FALSE, FALSE,
7032 EL_EMC_FAKE_ACID, -1, -1
7035 Xfake_acid_6, FALSE, FALSE,
7036 EL_EMC_FAKE_ACID, -1, -1
7039 Xfake_acid_7, FALSE, FALSE,
7040 EL_EMC_FAKE_ACID, -1, -1
7043 Xfake_acid_8, FALSE, FALSE,
7044 EL_EMC_FAKE_ACID, -1, -1
7047 Xsteel_1, TRUE, FALSE,
7048 EL_STEELWALL, -1, -1
7051 Xsteel_2, TRUE, FALSE,
7052 EL_EMC_STEELWALL_2, -1, -1
7055 Xsteel_3, TRUE, FALSE,
7056 EL_EMC_STEELWALL_3, -1, -1
7059 Xsteel_4, TRUE, FALSE,
7060 EL_EMC_STEELWALL_4, -1, -1
7063 Xwall_1, TRUE, FALSE,
7067 Xwall_2, TRUE, FALSE,
7068 EL_EMC_WALL_14, -1, -1
7071 Xwall_3, TRUE, FALSE,
7072 EL_EMC_WALL_15, -1, -1
7075 Xwall_4, TRUE, FALSE,
7076 EL_EMC_WALL_16, -1, -1
7079 Xround_wall_1, TRUE, FALSE,
7080 EL_WALL_SLIPPERY, -1, -1
7083 Xround_wall_2, TRUE, FALSE,
7084 EL_EMC_WALL_SLIPPERY_2, -1, -1
7087 Xround_wall_3, TRUE, FALSE,
7088 EL_EMC_WALL_SLIPPERY_3, -1, -1
7091 Xround_wall_4, TRUE, FALSE,
7092 EL_EMC_WALL_SLIPPERY_4, -1, -1
7095 Xdecor_1, TRUE, FALSE,
7096 EL_EMC_WALL_8, -1, -1
7099 Xdecor_2, TRUE, FALSE,
7100 EL_EMC_WALL_6, -1, -1
7103 Xdecor_3, TRUE, FALSE,
7104 EL_EMC_WALL_4, -1, -1
7107 Xdecor_4, TRUE, FALSE,
7108 EL_EMC_WALL_7, -1, -1
7111 Xdecor_5, TRUE, FALSE,
7112 EL_EMC_WALL_5, -1, -1
7115 Xdecor_6, TRUE, FALSE,
7116 EL_EMC_WALL_9, -1, -1
7119 Xdecor_7, TRUE, FALSE,
7120 EL_EMC_WALL_10, -1, -1
7123 Xdecor_8, TRUE, FALSE,
7124 EL_EMC_WALL_1, -1, -1
7127 Xdecor_9, TRUE, FALSE,
7128 EL_EMC_WALL_2, -1, -1
7131 Xdecor_10, TRUE, FALSE,
7132 EL_EMC_WALL_3, -1, -1
7135 Xdecor_11, TRUE, FALSE,
7136 EL_EMC_WALL_11, -1, -1
7139 Xdecor_12, TRUE, FALSE,
7140 EL_EMC_WALL_12, -1, -1
7143 Xalpha_0, TRUE, FALSE,
7144 EL_CHAR('0'), -1, -1
7147 Xalpha_1, TRUE, FALSE,
7148 EL_CHAR('1'), -1, -1
7151 Xalpha_2, TRUE, FALSE,
7152 EL_CHAR('2'), -1, -1
7155 Xalpha_3, TRUE, FALSE,
7156 EL_CHAR('3'), -1, -1
7159 Xalpha_4, TRUE, FALSE,
7160 EL_CHAR('4'), -1, -1
7163 Xalpha_5, TRUE, FALSE,
7164 EL_CHAR('5'), -1, -1
7167 Xalpha_6, TRUE, FALSE,
7168 EL_CHAR('6'), -1, -1
7171 Xalpha_7, TRUE, FALSE,
7172 EL_CHAR('7'), -1, -1
7175 Xalpha_8, TRUE, FALSE,
7176 EL_CHAR('8'), -1, -1
7179 Xalpha_9, TRUE, FALSE,
7180 EL_CHAR('9'), -1, -1
7183 Xalpha_excla, TRUE, FALSE,
7184 EL_CHAR('!'), -1, -1
7187 Xalpha_quote, TRUE, FALSE,
7188 EL_CHAR('"'), -1, -1
7191 Xalpha_comma, TRUE, FALSE,
7192 EL_CHAR(','), -1, -1
7195 Xalpha_minus, TRUE, FALSE,
7196 EL_CHAR('-'), -1, -1
7199 Xalpha_perio, TRUE, FALSE,
7200 EL_CHAR('.'), -1, -1
7203 Xalpha_colon, TRUE, FALSE,
7204 EL_CHAR(':'), -1, -1
7207 Xalpha_quest, TRUE, FALSE,
7208 EL_CHAR('?'), -1, -1
7211 Xalpha_a, TRUE, FALSE,
7212 EL_CHAR('A'), -1, -1
7215 Xalpha_b, TRUE, FALSE,
7216 EL_CHAR('B'), -1, -1
7219 Xalpha_c, TRUE, FALSE,
7220 EL_CHAR('C'), -1, -1
7223 Xalpha_d, TRUE, FALSE,
7224 EL_CHAR('D'), -1, -1
7227 Xalpha_e, TRUE, FALSE,
7228 EL_CHAR('E'), -1, -1
7231 Xalpha_f, TRUE, FALSE,
7232 EL_CHAR('F'), -1, -1
7235 Xalpha_g, TRUE, FALSE,
7236 EL_CHAR('G'), -1, -1
7239 Xalpha_h, TRUE, FALSE,
7240 EL_CHAR('H'), -1, -1
7243 Xalpha_i, TRUE, FALSE,
7244 EL_CHAR('I'), -1, -1
7247 Xalpha_j, TRUE, FALSE,
7248 EL_CHAR('J'), -1, -1
7251 Xalpha_k, TRUE, FALSE,
7252 EL_CHAR('K'), -1, -1
7255 Xalpha_l, TRUE, FALSE,
7256 EL_CHAR('L'), -1, -1
7259 Xalpha_m, TRUE, FALSE,
7260 EL_CHAR('M'), -1, -1
7263 Xalpha_n, TRUE, FALSE,
7264 EL_CHAR('N'), -1, -1
7267 Xalpha_o, TRUE, FALSE,
7268 EL_CHAR('O'), -1, -1
7271 Xalpha_p, TRUE, FALSE,
7272 EL_CHAR('P'), -1, -1
7275 Xalpha_q, TRUE, FALSE,
7276 EL_CHAR('Q'), -1, -1
7279 Xalpha_r, TRUE, FALSE,
7280 EL_CHAR('R'), -1, -1
7283 Xalpha_s, TRUE, FALSE,
7284 EL_CHAR('S'), -1, -1
7287 Xalpha_t, TRUE, FALSE,
7288 EL_CHAR('T'), -1, -1
7291 Xalpha_u, TRUE, FALSE,
7292 EL_CHAR('U'), -1, -1
7295 Xalpha_v, TRUE, FALSE,
7296 EL_CHAR('V'), -1, -1
7299 Xalpha_w, TRUE, FALSE,
7300 EL_CHAR('W'), -1, -1
7303 Xalpha_x, TRUE, FALSE,
7304 EL_CHAR('X'), -1, -1
7307 Xalpha_y, TRUE, FALSE,
7308 EL_CHAR('Y'), -1, -1
7311 Xalpha_z, TRUE, FALSE,
7312 EL_CHAR('Z'), -1, -1
7315 Xalpha_arrow_e, TRUE, FALSE,
7316 EL_CHAR('>'), -1, -1
7319 Xalpha_arrow_w, TRUE, FALSE,
7320 EL_CHAR('<'), -1, -1
7323 Xalpha_copyr, TRUE, FALSE,
7324 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
7328 Xboom_bug, FALSE, FALSE,
7329 EL_BUG, ACTION_EXPLODING, -1
7332 Xboom_bomb, FALSE, FALSE,
7333 EL_BOMB, ACTION_EXPLODING, -1
7336 Xboom_android, FALSE, FALSE,
7337 EL_EMC_ANDROID, ACTION_OTHER, -1
7340 Xboom_1, FALSE, FALSE,
7341 EL_DEFAULT, ACTION_EXPLODING, -1
7344 Xboom_2, FALSE, FALSE,
7345 EL_DEFAULT, ACTION_EXPLODING, -1
7348 Znormal, FALSE, FALSE,
7352 Zdynamite, FALSE, FALSE,
7356 Zplayer, FALSE, FALSE,
7360 ZBORDER, FALSE, FALSE,
7370 static struct Mapping_EM_to_RND_player
7379 em_player_mapping_list[] =
7383 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7387 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7391 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7395 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7399 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7403 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7407 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7411 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7415 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7419 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7423 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7427 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7431 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7435 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7439 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7443 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7447 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7451 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7455 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7459 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7463 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7467 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7471 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7475 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7479 EL_PLAYER_1, ACTION_DEFAULT, -1,
7483 EL_PLAYER_2, ACTION_DEFAULT, -1,
7487 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7491 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7495 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7499 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7503 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7507 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7511 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7515 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7519 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7523 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7527 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7531 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7535 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7539 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7543 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7547 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7551 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7555 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7559 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7563 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7567 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7571 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7575 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7579 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7583 EL_PLAYER_3, ACTION_DEFAULT, -1,
7587 EL_PLAYER_4, ACTION_DEFAULT, -1,
7596 int map_element_RND_to_EM(int element_rnd)
7598 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7599 static boolean mapping_initialized = FALSE;
7601 if (!mapping_initialized)
7605 /* return "Xalpha_quest" for all undefined elements in mapping array */
7606 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7607 mapping_RND_to_EM[i] = Xalpha_quest;
7609 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7610 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7611 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7612 em_object_mapping_list[i].element_em;
7614 mapping_initialized = TRUE;
7617 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7618 return mapping_RND_to_EM[element_rnd];
7620 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7625 int map_element_EM_to_RND(int element_em)
7627 static unsigned short mapping_EM_to_RND[TILE_MAX];
7628 static boolean mapping_initialized = FALSE;
7630 if (!mapping_initialized)
7634 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7635 for (i = 0; i < TILE_MAX; i++)
7636 mapping_EM_to_RND[i] = EL_UNKNOWN;
7638 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7639 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7640 em_object_mapping_list[i].element_rnd;
7642 mapping_initialized = TRUE;
7645 if (element_em >= 0 && element_em < TILE_MAX)
7646 return mapping_EM_to_RND[element_em];
7648 Error(ERR_WARN, "invalid EM level element %d", element_em);
7653 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7655 struct LevelInfo_EM *level_em = level->native_em_level;
7656 struct LEVEL *lev = level_em->lev;
7659 for (i = 0; i < TILE_MAX; i++)
7660 lev->android_array[i] = Xblank;
7662 for (i = 0; i < level->num_android_clone_elements; i++)
7664 int element_rnd = level->android_clone_element[i];
7665 int element_em = map_element_RND_to_EM(element_rnd);
7667 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7668 if (em_object_mapping_list[j].element_rnd == element_rnd)
7669 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7673 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7675 struct LevelInfo_EM *level_em = level->native_em_level;
7676 struct LEVEL *lev = level_em->lev;
7679 level->num_android_clone_elements = 0;
7681 for (i = 0; i < TILE_MAX; i++)
7683 int element_em = lev->android_array[i];
7685 boolean element_found = FALSE;
7687 if (element_em == Xblank)
7690 element_rnd = map_element_EM_to_RND(element_em);
7692 for (j = 0; j < level->num_android_clone_elements; j++)
7693 if (level->android_clone_element[j] == element_rnd)
7694 element_found = TRUE;
7698 level->android_clone_element[level->num_android_clone_elements++] =
7701 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7706 if (level->num_android_clone_elements == 0)
7708 level->num_android_clone_elements = 1;
7709 level->android_clone_element[0] = EL_EMPTY;
7713 int map_direction_RND_to_EM(int direction)
7715 return (direction == MV_UP ? 0 :
7716 direction == MV_RIGHT ? 1 :
7717 direction == MV_DOWN ? 2 :
7718 direction == MV_LEFT ? 3 :
7722 int map_direction_EM_to_RND(int direction)
7724 return (direction == 0 ? MV_UP :
7725 direction == 1 ? MV_RIGHT :
7726 direction == 2 ? MV_DOWN :
7727 direction == 3 ? MV_LEFT :
7731 int map_element_RND_to_SP(int element_rnd)
7733 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7735 if (element_rnd >= EL_SP_START &&
7736 element_rnd <= EL_SP_END)
7737 element_sp = element_rnd - EL_SP_START;
7738 else if (element_rnd == EL_EMPTY_SPACE)
7740 else if (element_rnd == EL_INVISIBLE_WALL)
7746 int map_element_SP_to_RND(int element_sp)
7748 int element_rnd = EL_UNKNOWN;
7750 if (element_sp >= 0x00 &&
7752 element_rnd = EL_SP_START + element_sp;
7753 else if (element_sp == 0x28)
7754 element_rnd = EL_INVISIBLE_WALL;
7759 int map_action_SP_to_RND(int action_sp)
7763 case actActive: return ACTION_ACTIVE;
7764 case actImpact: return ACTION_IMPACT;
7765 case actExploding: return ACTION_EXPLODING;
7766 case actDigging: return ACTION_DIGGING;
7767 case actSnapping: return ACTION_SNAPPING;
7768 case actCollecting: return ACTION_COLLECTING;
7769 case actPassing: return ACTION_PASSING;
7770 case actPushing: return ACTION_PUSHING;
7771 case actDropping: return ACTION_DROPPING;
7773 default: return ACTION_DEFAULT;
7777 int map_element_RND_to_MM(int element_rnd)
7779 return (element_rnd >= EL_MM_START_1 &&
7780 element_rnd <= EL_MM_END_1 ?
7781 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7783 element_rnd >= EL_MM_START_2 &&
7784 element_rnd <= EL_MM_END_2 ?
7785 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7787 element_rnd >= EL_CHAR_START &&
7788 element_rnd <= EL_CHAR_END ?
7789 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7791 element_rnd >= EL_MM_RUNTIME_START &&
7792 element_rnd <= EL_MM_RUNTIME_END ?
7793 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7795 element_rnd >= EL_MM_DUMMY_START &&
7796 element_rnd <= EL_MM_DUMMY_END ?
7797 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7799 EL_MM_EMPTY_NATIVE);
7802 int map_element_MM_to_RND(int element_mm)
7804 return (element_mm == EL_MM_EMPTY_NATIVE ||
7805 element_mm == EL_DF_EMPTY_NATIVE ?
7808 element_mm >= EL_MM_START_1_NATIVE &&
7809 element_mm <= EL_MM_END_1_NATIVE ?
7810 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7812 element_mm >= EL_MM_START_2_NATIVE &&
7813 element_mm <= EL_MM_END_2_NATIVE ?
7814 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7816 element_mm >= EL_MM_CHAR_START_NATIVE &&
7817 element_mm <= EL_MM_CHAR_END_NATIVE ?
7818 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7820 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7821 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7822 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7824 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7825 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7826 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7831 int map_action_MM_to_RND(int action_mm)
7833 /* all MM actions are defined to exactly match their RND counterparts */
7837 int map_sound_MM_to_RND(int sound_mm)
7841 case SND_MM_GAME_LEVELTIME_CHARGING:
7842 return SND_GAME_LEVELTIME_CHARGING;
7844 case SND_MM_GAME_HEALTH_CHARGING:
7845 return SND_GAME_HEALTH_CHARGING;
7848 return SND_UNDEFINED;
7852 int map_mm_wall_element(int element)
7854 return (element >= EL_MM_STEEL_WALL_START &&
7855 element <= EL_MM_STEEL_WALL_END ?
7858 element >= EL_MM_WOODEN_WALL_START &&
7859 element <= EL_MM_WOODEN_WALL_END ?
7862 element >= EL_MM_ICE_WALL_START &&
7863 element <= EL_MM_ICE_WALL_END ?
7866 element >= EL_MM_AMOEBA_WALL_START &&
7867 element <= EL_MM_AMOEBA_WALL_END ?
7870 element >= EL_DF_STEEL_WALL_START &&
7871 element <= EL_DF_STEEL_WALL_END ?
7874 element >= EL_DF_WOODEN_WALL_START &&
7875 element <= EL_DF_WOODEN_WALL_END ?
7881 int map_mm_wall_element_editor(int element)
7885 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7886 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7887 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7888 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7889 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7890 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7892 default: return element;
7896 int get_next_element(int element)
7900 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7901 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7902 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7903 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7904 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7905 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7906 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7907 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7908 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7909 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7910 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7912 default: return element;
7916 int el2img_mm(int element_mm)
7918 return el2img(map_element_MM_to_RND(element_mm));
7921 int el_act_dir2img(int element, int action, int direction)
7923 element = GFX_ELEMENT(element);
7924 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7926 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7927 return element_info[element].direction_graphic[action][direction];
7930 static int el_act_dir2crm(int element, int action, int direction)
7932 element = GFX_ELEMENT(element);
7933 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7935 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7936 return element_info[element].direction_crumbled[action][direction];
7939 int el_act2img(int element, int action)
7941 element = GFX_ELEMENT(element);
7943 return element_info[element].graphic[action];
7946 int el_act2crm(int element, int action)
7948 element = GFX_ELEMENT(element);
7950 return element_info[element].crumbled[action];
7953 int el_dir2img(int element, int direction)
7955 element = GFX_ELEMENT(element);
7957 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7960 int el2baseimg(int element)
7962 return element_info[element].graphic[ACTION_DEFAULT];
7965 int el2img(int element)
7967 element = GFX_ELEMENT(element);
7969 return element_info[element].graphic[ACTION_DEFAULT];
7972 int el2edimg(int element)
7974 element = GFX_ELEMENT(element);
7976 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7979 int el2preimg(int element)
7981 element = GFX_ELEMENT(element);
7983 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7986 int el2panelimg(int element)
7988 element = GFX_ELEMENT(element);
7990 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7993 int font2baseimg(int font_nr)
7995 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7998 int getBeltNrFromBeltElement(int element)
8000 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
8001 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
8002 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
8005 int getBeltNrFromBeltActiveElement(int element)
8007 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
8008 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
8009 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
8012 int getBeltNrFromBeltSwitchElement(int element)
8014 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
8015 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
8016 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
8019 int getBeltDirNrFromBeltElement(int element)
8021 static int belt_base_element[4] =
8023 EL_CONVEYOR_BELT_1_LEFT,
8024 EL_CONVEYOR_BELT_2_LEFT,
8025 EL_CONVEYOR_BELT_3_LEFT,
8026 EL_CONVEYOR_BELT_4_LEFT
8029 int belt_nr = getBeltNrFromBeltElement(element);
8030 int belt_dir_nr = element - belt_base_element[belt_nr];
8032 return (belt_dir_nr % 3);
8035 int getBeltDirNrFromBeltSwitchElement(int element)
8037 static int belt_base_element[4] =
8039 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8040 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8041 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8042 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8045 int belt_nr = getBeltNrFromBeltSwitchElement(element);
8046 int belt_dir_nr = element - belt_base_element[belt_nr];
8048 return (belt_dir_nr % 3);
8051 int getBeltDirFromBeltElement(int element)
8053 static int belt_move_dir[3] =
8060 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
8062 return belt_move_dir[belt_dir_nr];
8065 int getBeltDirFromBeltSwitchElement(int element)
8067 static int belt_move_dir[3] =
8074 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
8076 return belt_move_dir[belt_dir_nr];
8079 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8081 static int belt_base_element[4] =
8083 EL_CONVEYOR_BELT_1_LEFT,
8084 EL_CONVEYOR_BELT_2_LEFT,
8085 EL_CONVEYOR_BELT_3_LEFT,
8086 EL_CONVEYOR_BELT_4_LEFT
8089 return belt_base_element[belt_nr] + belt_dir_nr;
8092 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8094 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8096 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8099 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8101 static int belt_base_element[4] =
8103 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8104 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8105 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8106 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8109 return belt_base_element[belt_nr] + belt_dir_nr;
8112 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8114 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8116 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8119 boolean getTeamMode_EM(void)
8121 return game.team_mode || network_playing;
8124 int getGameFrameDelay_EM(int native_em_game_frame_delay)
8126 int game_frame_delay_value;
8128 game_frame_delay_value =
8129 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
8130 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
8133 if (tape.playing && tape.warp_forward && !tape.pausing)
8134 game_frame_delay_value = 0;
8136 return game_frame_delay_value;
8139 unsigned int InitRND(int seed)
8141 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
8142 return InitEngineRandom_EM(seed);
8143 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
8144 return InitEngineRandom_SP(seed);
8145 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
8146 return InitEngineRandom_MM(seed);
8148 return InitEngineRandom_RND(seed);
8151 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8152 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8154 inline static int get_effective_element_EM(int tile, int frame_em)
8156 int element = object_mapping[tile].element_rnd;
8157 int action = object_mapping[tile].action;
8158 boolean is_backside = object_mapping[tile].is_backside;
8159 boolean action_removing = (action == ACTION_DIGGING ||
8160 action == ACTION_SNAPPING ||
8161 action == ACTION_COLLECTING);
8167 case Yacid_splash_eB:
8168 case Yacid_splash_wB:
8169 return (frame_em > 5 ? EL_EMPTY : element);
8175 else /* frame_em == 7 */
8179 case Yacid_splash_eB:
8180 case Yacid_splash_wB:
8183 case Yemerald_stone:
8186 case Ydiamond_stone:
8190 case Xdrip_stretchB:
8209 case Xsand_stonein_1:
8210 case Xsand_stonein_2:
8211 case Xsand_stonein_3:
8212 case Xsand_stonein_4:
8216 return (is_backside || action_removing ? EL_EMPTY : element);
8221 inline static boolean check_linear_animation_EM(int tile)
8225 case Xsand_stonesand_1:
8226 case Xsand_stonesand_quickout_1:
8227 case Xsand_sandstone_1:
8228 case Xsand_stonein_1:
8229 case Xsand_stoneout_1:
8248 case Yacid_splash_eB:
8249 case Yacid_splash_wB:
8250 case Yemerald_stone:
8257 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
8258 boolean has_crumbled_graphics,
8259 int crumbled, int sync_frame)
8261 /* if element can be crumbled, but certain action graphics are just empty
8262 space (like instantly snapping sand to empty space in 1 frame), do not
8263 treat these empty space graphics as crumbled graphics in EMC engine */
8264 if (crumbled == IMG_EMPTY_SPACE)
8265 has_crumbled_graphics = FALSE;
8267 if (has_crumbled_graphics)
8269 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8270 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8271 g_crumbled->anim_delay,
8272 g_crumbled->anim_mode,
8273 g_crumbled->anim_start_frame,
8276 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8277 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8279 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8280 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
8282 g_em->has_crumbled_graphics = TRUE;
8286 g_em->crumbled_bitmap = NULL;
8287 g_em->crumbled_src_x = 0;
8288 g_em->crumbled_src_y = 0;
8289 g_em->crumbled_border_size = 0;
8290 g_em->crumbled_tile_size = 0;
8292 g_em->has_crumbled_graphics = FALSE;
8297 void ResetGfxAnimation_EM(int x, int y, int tile)
8303 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
8304 int tile, int frame_em, int x, int y)
8306 int action = object_mapping[tile].action;
8307 int direction = object_mapping[tile].direction;
8308 int effective_element = get_effective_element_EM(tile, frame_em);
8309 int graphic = (direction == MV_NONE ?
8310 el_act2img(effective_element, action) :
8311 el_act_dir2img(effective_element, action, direction));
8312 struct GraphicInfo *g = &graphic_info[graphic];
8314 boolean action_removing = (action == ACTION_DIGGING ||
8315 action == ACTION_SNAPPING ||
8316 action == ACTION_COLLECTING);
8317 boolean action_moving = (action == ACTION_FALLING ||
8318 action == ACTION_MOVING ||
8319 action == ACTION_PUSHING ||
8320 action == ACTION_EATING ||
8321 action == ACTION_FILLING ||
8322 action == ACTION_EMPTYING);
8323 boolean action_falling = (action == ACTION_FALLING ||
8324 action == ACTION_FILLING ||
8325 action == ACTION_EMPTYING);
8327 /* special case: graphic uses "2nd movement tile" and has defined
8328 7 frames for movement animation (or less) => use default graphic
8329 for last (8th) frame which ends the movement animation */
8330 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8332 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
8333 graphic = (direction == MV_NONE ?
8334 el_act2img(effective_element, action) :
8335 el_act_dir2img(effective_element, action, direction));
8337 g = &graphic_info[graphic];
8340 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8344 else if (action_moving)
8346 boolean is_backside = object_mapping[tile].is_backside;
8350 int direction = object_mapping[tile].direction;
8351 int move_dir = (action_falling ? MV_DOWN : direction);
8356 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8357 if (g->double_movement && frame_em == 0)
8361 if (move_dir == MV_LEFT)
8362 GfxFrame[x - 1][y] = GfxFrame[x][y];
8363 else if (move_dir == MV_RIGHT)
8364 GfxFrame[x + 1][y] = GfxFrame[x][y];
8365 else if (move_dir == MV_UP)
8366 GfxFrame[x][y - 1] = GfxFrame[x][y];
8367 else if (move_dir == MV_DOWN)
8368 GfxFrame[x][y + 1] = GfxFrame[x][y];
8375 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8376 if (tile == Xsand_stonesand_quickout_1 ||
8377 tile == Xsand_stonesand_quickout_2)
8381 if (graphic_info[graphic].anim_global_sync)
8382 sync_frame = FrameCounter;
8383 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8384 sync_frame = GfxFrame[x][y];
8386 sync_frame = 0; /* playfield border (pseudo steel) */
8388 SetRandomAnimationValue(x, y);
8390 int frame = getAnimationFrame(g->anim_frames,
8393 g->anim_start_frame,
8396 g_em->unique_identifier =
8397 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8400 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8401 int tile, int frame_em, int x, int y)
8403 int action = object_mapping[tile].action;
8404 int direction = object_mapping[tile].direction;
8405 boolean is_backside = object_mapping[tile].is_backside;
8406 int effective_element = get_effective_element_EM(tile, frame_em);
8407 int effective_action = action;
8408 int graphic = (direction == MV_NONE ?
8409 el_act2img(effective_element, effective_action) :
8410 el_act_dir2img(effective_element, effective_action,
8412 int crumbled = (direction == MV_NONE ?
8413 el_act2crm(effective_element, effective_action) :
8414 el_act_dir2crm(effective_element, effective_action,
8416 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8417 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8418 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8419 struct GraphicInfo *g = &graphic_info[graphic];
8422 /* special case: graphic uses "2nd movement tile" and has defined
8423 7 frames for movement animation (or less) => use default graphic
8424 for last (8th) frame which ends the movement animation */
8425 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8427 effective_action = ACTION_DEFAULT;
8428 graphic = (direction == MV_NONE ?
8429 el_act2img(effective_element, effective_action) :
8430 el_act_dir2img(effective_element, effective_action,
8432 crumbled = (direction == MV_NONE ?
8433 el_act2crm(effective_element, effective_action) :
8434 el_act_dir2crm(effective_element, effective_action,
8437 g = &graphic_info[graphic];
8440 if (graphic_info[graphic].anim_global_sync)
8441 sync_frame = FrameCounter;
8442 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8443 sync_frame = GfxFrame[x][y];
8445 sync_frame = 0; /* playfield border (pseudo steel) */
8447 SetRandomAnimationValue(x, y);
8449 int frame = getAnimationFrame(g->anim_frames,
8452 g->anim_start_frame,
8455 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8456 g->double_movement && is_backside);
8458 /* (updating the "crumbled" graphic definitions is probably not really needed,
8459 as animations for crumbled graphics can't be longer than one EMC cycle) */
8460 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8464 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8465 int player_nr, int anim, int frame_em)
8467 int element = player_mapping[player_nr][anim].element_rnd;
8468 int action = player_mapping[player_nr][anim].action;
8469 int direction = player_mapping[player_nr][anim].direction;
8470 int graphic = (direction == MV_NONE ?
8471 el_act2img(element, action) :
8472 el_act_dir2img(element, action, direction));
8473 struct GraphicInfo *g = &graphic_info[graphic];
8476 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8478 stored_player[player_nr].StepFrame = frame_em;
8480 sync_frame = stored_player[player_nr].Frame;
8482 int frame = getAnimationFrame(g->anim_frames,
8485 g->anim_start_frame,
8488 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8489 &g_em->src_x, &g_em->src_y, FALSE);
8492 void InitGraphicInfo_EM(void)
8497 int num_em_gfx_errors = 0;
8499 if (graphic_info_em_object[0][0].bitmap == NULL)
8501 /* EM graphics not yet initialized in em_open_all() */
8506 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8509 /* always start with reliable default values */
8510 for (i = 0; i < TILE_MAX; i++)
8512 object_mapping[i].element_rnd = EL_UNKNOWN;
8513 object_mapping[i].is_backside = FALSE;
8514 object_mapping[i].action = ACTION_DEFAULT;
8515 object_mapping[i].direction = MV_NONE;
8518 /* always start with reliable default values */
8519 for (p = 0; p < MAX_PLAYERS; p++)
8521 for (i = 0; i < SPR_MAX; i++)
8523 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8524 player_mapping[p][i].action = ACTION_DEFAULT;
8525 player_mapping[p][i].direction = MV_NONE;
8529 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8531 int e = em_object_mapping_list[i].element_em;
8533 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8534 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8536 if (em_object_mapping_list[i].action != -1)
8537 object_mapping[e].action = em_object_mapping_list[i].action;
8539 if (em_object_mapping_list[i].direction != -1)
8540 object_mapping[e].direction =
8541 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8544 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8546 int a = em_player_mapping_list[i].action_em;
8547 int p = em_player_mapping_list[i].player_nr;
8549 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8551 if (em_player_mapping_list[i].action != -1)
8552 player_mapping[p][a].action = em_player_mapping_list[i].action;
8554 if (em_player_mapping_list[i].direction != -1)
8555 player_mapping[p][a].direction =
8556 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8559 for (i = 0; i < TILE_MAX; i++)
8561 int element = object_mapping[i].element_rnd;
8562 int action = object_mapping[i].action;
8563 int direction = object_mapping[i].direction;
8564 boolean is_backside = object_mapping[i].is_backside;
8565 boolean action_exploding = ((action == ACTION_EXPLODING ||
8566 action == ACTION_SMASHED_BY_ROCK ||
8567 action == ACTION_SMASHED_BY_SPRING) &&
8568 element != EL_DIAMOND);
8569 boolean action_active = (action == ACTION_ACTIVE);
8570 boolean action_other = (action == ACTION_OTHER);
8572 for (j = 0; j < 8; j++)
8574 int effective_element = get_effective_element_EM(i, j);
8575 int effective_action = (j < 7 ? action :
8576 i == Xdrip_stretch ? action :
8577 i == Xdrip_stretchB ? action :
8578 i == Ydrip_s1 ? action :
8579 i == Ydrip_s1B ? action :
8580 i == Xball_1B ? action :
8581 i == Xball_2 ? action :
8582 i == Xball_2B ? action :
8583 i == Yball_eat ? action :
8584 i == Ykey_1_eat ? action :
8585 i == Ykey_2_eat ? action :
8586 i == Ykey_3_eat ? action :
8587 i == Ykey_4_eat ? action :
8588 i == Ykey_5_eat ? action :
8589 i == Ykey_6_eat ? action :
8590 i == Ykey_7_eat ? action :
8591 i == Ykey_8_eat ? action :
8592 i == Ylenses_eat ? action :
8593 i == Ymagnify_eat ? action :
8594 i == Ygrass_eat ? action :
8595 i == Ydirt_eat ? action :
8596 i == Xsand_stonein_1 ? action :
8597 i == Xsand_stonein_2 ? action :
8598 i == Xsand_stonein_3 ? action :
8599 i == Xsand_stonein_4 ? action :
8600 i == Xsand_stoneout_1 ? action :
8601 i == Xsand_stoneout_2 ? action :
8602 i == Xboom_android ? ACTION_EXPLODING :
8603 action_exploding ? ACTION_EXPLODING :
8604 action_active ? action :
8605 action_other ? action :
8607 int graphic = (el_act_dir2img(effective_element, effective_action,
8609 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8611 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8612 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8613 boolean has_action_graphics = (graphic != base_graphic);
8614 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8615 struct GraphicInfo *g = &graphic_info[graphic];
8616 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8619 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8620 boolean special_animation = (action != ACTION_DEFAULT &&
8621 g->anim_frames == 3 &&
8622 g->anim_delay == 2 &&
8623 g->anim_mode & ANIM_LINEAR);
8624 int sync_frame = (i == Xdrip_stretch ? 7 :
8625 i == Xdrip_stretchB ? 7 :
8626 i == Ydrip_s2 ? j + 8 :
8627 i == Ydrip_s2B ? j + 8 :
8636 i == Xfake_acid_1 ? 0 :
8637 i == Xfake_acid_2 ? 10 :
8638 i == Xfake_acid_3 ? 20 :
8639 i == Xfake_acid_4 ? 30 :
8640 i == Xfake_acid_5 ? 40 :
8641 i == Xfake_acid_6 ? 50 :
8642 i == Xfake_acid_7 ? 60 :
8643 i == Xfake_acid_8 ? 70 :
8645 i == Xball_2B ? j + 8 :
8646 i == Yball_eat ? j + 1 :
8647 i == Ykey_1_eat ? j + 1 :
8648 i == Ykey_2_eat ? j + 1 :
8649 i == Ykey_3_eat ? j + 1 :
8650 i == Ykey_4_eat ? j + 1 :
8651 i == Ykey_5_eat ? j + 1 :
8652 i == Ykey_6_eat ? j + 1 :
8653 i == Ykey_7_eat ? j + 1 :
8654 i == Ykey_8_eat ? j + 1 :
8655 i == Ylenses_eat ? j + 1 :
8656 i == Ymagnify_eat ? j + 1 :
8657 i == Ygrass_eat ? j + 1 :
8658 i == Ydirt_eat ? j + 1 :
8659 i == Xamoeba_1 ? 0 :
8660 i == Xamoeba_2 ? 1 :
8661 i == Xamoeba_3 ? 2 :
8662 i == Xamoeba_4 ? 3 :
8663 i == Xamoeba_5 ? 0 :
8664 i == Xamoeba_6 ? 1 :
8665 i == Xamoeba_7 ? 2 :
8666 i == Xamoeba_8 ? 3 :
8667 i == Xexit_2 ? j + 8 :
8668 i == Xexit_3 ? j + 16 :
8669 i == Xdynamite_1 ? 0 :
8670 i == Xdynamite_2 ? 8 :
8671 i == Xdynamite_3 ? 16 :
8672 i == Xdynamite_4 ? 24 :
8673 i == Xsand_stonein_1 ? j + 1 :
8674 i == Xsand_stonein_2 ? j + 9 :
8675 i == Xsand_stonein_3 ? j + 17 :
8676 i == Xsand_stonein_4 ? j + 25 :
8677 i == Xsand_stoneout_1 && j == 0 ? 0 :
8678 i == Xsand_stoneout_1 && j == 1 ? 0 :
8679 i == Xsand_stoneout_1 && j == 2 ? 1 :
8680 i == Xsand_stoneout_1 && j == 3 ? 2 :
8681 i == Xsand_stoneout_1 && j == 4 ? 2 :
8682 i == Xsand_stoneout_1 && j == 5 ? 3 :
8683 i == Xsand_stoneout_1 && j == 6 ? 4 :
8684 i == Xsand_stoneout_1 && j == 7 ? 4 :
8685 i == Xsand_stoneout_2 && j == 0 ? 5 :
8686 i == Xsand_stoneout_2 && j == 1 ? 6 :
8687 i == Xsand_stoneout_2 && j == 2 ? 7 :
8688 i == Xsand_stoneout_2 && j == 3 ? 8 :
8689 i == Xsand_stoneout_2 && j == 4 ? 9 :
8690 i == Xsand_stoneout_2 && j == 5 ? 11 :
8691 i == Xsand_stoneout_2 && j == 6 ? 13 :
8692 i == Xsand_stoneout_2 && j == 7 ? 15 :
8693 i == Xboom_bug && j == 1 ? 2 :
8694 i == Xboom_bug && j == 2 ? 2 :
8695 i == Xboom_bug && j == 3 ? 4 :
8696 i == Xboom_bug && j == 4 ? 4 :
8697 i == Xboom_bug && j == 5 ? 2 :
8698 i == Xboom_bug && j == 6 ? 2 :
8699 i == Xboom_bug && j == 7 ? 0 :
8700 i == Xboom_bomb && j == 1 ? 2 :
8701 i == Xboom_bomb && j == 2 ? 2 :
8702 i == Xboom_bomb && j == 3 ? 4 :
8703 i == Xboom_bomb && j == 4 ? 4 :
8704 i == Xboom_bomb && j == 5 ? 2 :
8705 i == Xboom_bomb && j == 6 ? 2 :
8706 i == Xboom_bomb && j == 7 ? 0 :
8707 i == Xboom_android && j == 7 ? 6 :
8708 i == Xboom_1 && j == 1 ? 2 :
8709 i == Xboom_1 && j == 2 ? 2 :
8710 i == Xboom_1 && j == 3 ? 4 :
8711 i == Xboom_1 && j == 4 ? 4 :
8712 i == Xboom_1 && j == 5 ? 6 :
8713 i == Xboom_1 && j == 6 ? 6 :
8714 i == Xboom_1 && j == 7 ? 8 :
8715 i == Xboom_2 && j == 0 ? 8 :
8716 i == Xboom_2 && j == 1 ? 8 :
8717 i == Xboom_2 && j == 2 ? 10 :
8718 i == Xboom_2 && j == 3 ? 10 :
8719 i == Xboom_2 && j == 4 ? 10 :
8720 i == Xboom_2 && j == 5 ? 12 :
8721 i == Xboom_2 && j == 6 ? 12 :
8722 i == Xboom_2 && j == 7 ? 12 :
8723 special_animation && j == 4 ? 3 :
8724 effective_action != action ? 0 :
8728 Bitmap *debug_bitmap = g_em->bitmap;
8729 int debug_src_x = g_em->src_x;
8730 int debug_src_y = g_em->src_y;
8733 int frame = getAnimationFrame(g->anim_frames,
8736 g->anim_start_frame,
8739 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8740 g->double_movement && is_backside);
8742 g_em->bitmap = src_bitmap;
8743 g_em->src_x = src_x;
8744 g_em->src_y = src_y;
8745 g_em->src_offset_x = 0;
8746 g_em->src_offset_y = 0;
8747 g_em->dst_offset_x = 0;
8748 g_em->dst_offset_y = 0;
8749 g_em->width = TILEX;
8750 g_em->height = TILEY;
8752 g_em->preserve_background = FALSE;
8754 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8757 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8758 effective_action == ACTION_MOVING ||
8759 effective_action == ACTION_PUSHING ||
8760 effective_action == ACTION_EATING)) ||
8761 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8762 effective_action == ACTION_EMPTYING)))
8765 (effective_action == ACTION_FALLING ||
8766 effective_action == ACTION_FILLING ||
8767 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8768 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8769 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8770 int num_steps = (i == Ydrip_s1 ? 16 :
8771 i == Ydrip_s1B ? 16 :
8772 i == Ydrip_s2 ? 16 :
8773 i == Ydrip_s2B ? 16 :
8774 i == Xsand_stonein_1 ? 32 :
8775 i == Xsand_stonein_2 ? 32 :
8776 i == Xsand_stonein_3 ? 32 :
8777 i == Xsand_stonein_4 ? 32 :
8778 i == Xsand_stoneout_1 ? 16 :
8779 i == Xsand_stoneout_2 ? 16 : 8);
8780 int cx = ABS(dx) * (TILEX / num_steps);
8781 int cy = ABS(dy) * (TILEY / num_steps);
8782 int step_frame = (i == Ydrip_s2 ? j + 8 :
8783 i == Ydrip_s2B ? j + 8 :
8784 i == Xsand_stonein_2 ? j + 8 :
8785 i == Xsand_stonein_3 ? j + 16 :
8786 i == Xsand_stonein_4 ? j + 24 :
8787 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8788 int step = (is_backside ? step_frame : num_steps - step_frame);
8790 if (is_backside) /* tile where movement starts */
8792 if (dx < 0 || dy < 0)
8794 g_em->src_offset_x = cx * step;
8795 g_em->src_offset_y = cy * step;
8799 g_em->dst_offset_x = cx * step;
8800 g_em->dst_offset_y = cy * step;
8803 else /* tile where movement ends */
8805 if (dx < 0 || dy < 0)
8807 g_em->dst_offset_x = cx * step;
8808 g_em->dst_offset_y = cy * step;
8812 g_em->src_offset_x = cx * step;
8813 g_em->src_offset_y = cy * step;
8817 g_em->width = TILEX - cx * step;
8818 g_em->height = TILEY - cy * step;
8821 /* create unique graphic identifier to decide if tile must be redrawn */
8822 /* bit 31 - 16 (16 bit): EM style graphic
8823 bit 15 - 12 ( 4 bit): EM style frame
8824 bit 11 - 6 ( 6 bit): graphic width
8825 bit 5 - 0 ( 6 bit): graphic height */
8826 g_em->unique_identifier =
8827 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8831 /* skip check for EMC elements not contained in original EMC artwork */
8832 if (element == EL_EMC_FAKE_ACID)
8835 if (g_em->bitmap != debug_bitmap ||
8836 g_em->src_x != debug_src_x ||
8837 g_em->src_y != debug_src_y ||
8838 g_em->src_offset_x != 0 ||
8839 g_em->src_offset_y != 0 ||
8840 g_em->dst_offset_x != 0 ||
8841 g_em->dst_offset_y != 0 ||
8842 g_em->width != TILEX ||
8843 g_em->height != TILEY)
8845 static int last_i = -1;
8853 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8854 i, element, element_info[element].token_name,
8855 element_action_info[effective_action].suffix, direction);
8857 if (element != effective_element)
8858 printf(" [%d ('%s')]",
8860 element_info[effective_element].token_name);
8864 if (g_em->bitmap != debug_bitmap)
8865 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8866 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8868 if (g_em->src_x != debug_src_x ||
8869 g_em->src_y != debug_src_y)
8870 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8871 j, (is_backside ? 'B' : 'F'),
8872 g_em->src_x, g_em->src_y,
8873 g_em->src_x / 32, g_em->src_y / 32,
8874 debug_src_x, debug_src_y,
8875 debug_src_x / 32, debug_src_y / 32);
8877 if (g_em->src_offset_x != 0 ||
8878 g_em->src_offset_y != 0 ||
8879 g_em->dst_offset_x != 0 ||
8880 g_em->dst_offset_y != 0)
8881 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8883 g_em->src_offset_x, g_em->src_offset_y,
8884 g_em->dst_offset_x, g_em->dst_offset_y);
8886 if (g_em->width != TILEX ||
8887 g_em->height != TILEY)
8888 printf(" %d (%d): size %d,%d should be %d,%d\n",
8890 g_em->width, g_em->height, TILEX, TILEY);
8892 num_em_gfx_errors++;
8899 for (i = 0; i < TILE_MAX; i++)
8901 for (j = 0; j < 8; j++)
8903 int element = object_mapping[i].element_rnd;
8904 int action = object_mapping[i].action;
8905 int direction = object_mapping[i].direction;
8906 boolean is_backside = object_mapping[i].is_backside;
8907 int graphic_action = el_act_dir2img(element, action, direction);
8908 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8910 if ((action == ACTION_SMASHED_BY_ROCK ||
8911 action == ACTION_SMASHED_BY_SPRING ||
8912 action == ACTION_EATING) &&
8913 graphic_action == graphic_default)
8915 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8916 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8917 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8918 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8921 /* no separate animation for "smashed by rock" -- use rock instead */
8922 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8923 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8925 g_em->bitmap = g_xx->bitmap;
8926 g_em->src_x = g_xx->src_x;
8927 g_em->src_y = g_xx->src_y;
8928 g_em->src_offset_x = g_xx->src_offset_x;
8929 g_em->src_offset_y = g_xx->src_offset_y;
8930 g_em->dst_offset_x = g_xx->dst_offset_x;
8931 g_em->dst_offset_y = g_xx->dst_offset_y;
8932 g_em->width = g_xx->width;
8933 g_em->height = g_xx->height;
8934 g_em->unique_identifier = g_xx->unique_identifier;
8937 g_em->preserve_background = TRUE;
8942 for (p = 0; p < MAX_PLAYERS; p++)
8944 for (i = 0; i < SPR_MAX; i++)
8946 int element = player_mapping[p][i].element_rnd;
8947 int action = player_mapping[p][i].action;
8948 int direction = player_mapping[p][i].direction;
8950 for (j = 0; j < 8; j++)
8952 int effective_element = element;
8953 int effective_action = action;
8954 int graphic = (direction == MV_NONE ?
8955 el_act2img(effective_element, effective_action) :
8956 el_act_dir2img(effective_element, effective_action,
8958 struct GraphicInfo *g = &graphic_info[graphic];
8959 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8965 Bitmap *debug_bitmap = g_em->bitmap;
8966 int debug_src_x = g_em->src_x;
8967 int debug_src_y = g_em->src_y;
8970 int frame = getAnimationFrame(g->anim_frames,
8973 g->anim_start_frame,
8976 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8978 g_em->bitmap = src_bitmap;
8979 g_em->src_x = src_x;
8980 g_em->src_y = src_y;
8981 g_em->src_offset_x = 0;
8982 g_em->src_offset_y = 0;
8983 g_em->dst_offset_x = 0;
8984 g_em->dst_offset_y = 0;
8985 g_em->width = TILEX;
8986 g_em->height = TILEY;
8990 /* skip check for EMC elements not contained in original EMC artwork */
8991 if (element == EL_PLAYER_3 ||
8992 element == EL_PLAYER_4)
8995 if (g_em->bitmap != debug_bitmap ||
8996 g_em->src_x != debug_src_x ||
8997 g_em->src_y != debug_src_y)
8999 static int last_i = -1;
9007 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
9008 p, i, element, element_info[element].token_name,
9009 element_action_info[effective_action].suffix, direction);
9011 if (element != effective_element)
9012 printf(" [%d ('%s')]",
9014 element_info[effective_element].token_name);
9018 if (g_em->bitmap != debug_bitmap)
9019 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
9020 j, (int)(g_em->bitmap), (int)(debug_bitmap));
9022 if (g_em->src_x != debug_src_x ||
9023 g_em->src_y != debug_src_y)
9024 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
9026 g_em->src_x, g_em->src_y,
9027 g_em->src_x / 32, g_em->src_y / 32,
9028 debug_src_x, debug_src_y,
9029 debug_src_x / 32, debug_src_y / 32);
9031 num_em_gfx_errors++;
9041 printf("::: [%d errors found]\n", num_em_gfx_errors);
9047 static void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
9048 boolean any_player_moving,
9049 boolean any_player_snapping,
9050 boolean any_player_dropping)
9052 if (frame == 0 && !any_player_dropping)
9054 if (!local_player->was_waiting)
9056 if (!CheckSaveEngineSnapshotToList())
9059 local_player->was_waiting = TRUE;
9062 else if (any_player_moving || any_player_snapping || any_player_dropping)
9064 local_player->was_waiting = FALSE;
9068 static void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
9069 boolean murphy_is_dropping)
9071 if (murphy_is_waiting)
9073 if (!local_player->was_waiting)
9075 if (!CheckSaveEngineSnapshotToList())
9078 local_player->was_waiting = TRUE;
9083 local_player->was_waiting = FALSE;
9087 static void CheckSaveEngineSnapshot_MM(boolean element_clicked,
9088 boolean button_released)
9090 if (button_released)
9092 if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE)
9093 CheckSaveEngineSnapshotToList();
9095 else if (element_clicked)
9097 if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE)
9098 CheckSaveEngineSnapshotToList();
9100 game.snapshot.changed_action = TRUE;
9104 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
9105 boolean any_player_moving,
9106 boolean any_player_snapping,
9107 boolean any_player_dropping)
9109 if (tape.single_step && tape.recording && !tape.pausing)
9110 if (frame == 0 && !any_player_dropping)
9111 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9113 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
9114 any_player_snapping, any_player_dropping);
9117 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
9118 boolean murphy_is_dropping)
9120 boolean murphy_starts_dropping = FALSE;
9123 for (i = 0; i < MAX_PLAYERS; i++)
9124 if (stored_player[i].force_dropping)
9125 murphy_starts_dropping = TRUE;
9127 if (tape.single_step && tape.recording && !tape.pausing)
9128 if (murphy_is_waiting && !murphy_starts_dropping)
9129 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9131 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
9134 void CheckSingleStepMode_MM(boolean element_clicked,
9135 boolean button_released)
9137 if (tape.single_step && tape.recording && !tape.pausing)
9138 if (button_released)
9139 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9141 CheckSaveEngineSnapshot_MM(element_clicked, button_released);
9144 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
9145 int graphic, int sync_frame, int x, int y)
9147 int frame = getGraphicAnimationFrame(graphic, sync_frame);
9149 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
9152 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9154 return (IS_NEXT_FRAME(sync_frame, graphic));
9157 int getGraphicInfo_Delay(int graphic)
9159 return graphic_info[graphic].anim_delay;
9162 void PlayMenuSoundExt(int sound)
9164 if (sound == SND_UNDEFINED)
9167 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9168 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9171 if (IS_LOOP_SOUND(sound))
9172 PlaySoundLoop(sound);
9177 void PlayMenuSound(void)
9179 PlayMenuSoundExt(menu.sound[game_status]);
9182 void PlayMenuSoundStereo(int sound, int stereo_position)
9184 if (sound == SND_UNDEFINED)
9187 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9188 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9191 if (IS_LOOP_SOUND(sound))
9192 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9194 PlaySoundStereo(sound, stereo_position);
9197 void PlayMenuSoundIfLoopExt(int sound)
9199 if (sound == SND_UNDEFINED)
9202 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9203 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9206 if (IS_LOOP_SOUND(sound))
9207 PlaySoundLoop(sound);
9210 void PlayMenuSoundIfLoop(void)
9212 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9215 void PlayMenuMusicExt(int music)
9217 if (music == MUS_UNDEFINED)
9220 if (!setup.sound_music)
9223 if (IS_LOOP_MUSIC(music))
9224 PlayMusicLoop(music);
9229 void PlayMenuMusic(void)
9231 char *curr_music = getCurrentlyPlayingMusicFilename();
9232 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9234 if (!strEqual(curr_music, next_music))
9235 PlayMenuMusicExt(menu.music[game_status]);
9238 void PlayMenuSoundsAndMusic(void)
9244 static void FadeMenuSounds(void)
9249 static void FadeMenuMusic(void)
9251 char *curr_music = getCurrentlyPlayingMusicFilename();
9252 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9254 if (!strEqual(curr_music, next_music))
9258 void FadeMenuSoundsAndMusic(void)
9264 void PlaySoundActivating(void)
9267 PlaySound(SND_MENU_ITEM_ACTIVATING);
9271 void PlaySoundSelecting(void)
9274 PlaySound(SND_MENU_ITEM_SELECTING);
9278 void ToggleFullscreenOrChangeWindowScalingIfNeeded(void)
9280 boolean change_fullscreen = (setup.fullscreen !=
9281 video.fullscreen_enabled);
9282 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9283 setup.window_scaling_percent !=
9284 video.window_scaling_percent);
9286 if (change_window_scaling_percent && video.fullscreen_enabled)
9289 if (!change_window_scaling_percent && !video.fullscreen_available)
9292 #if defined(TARGET_SDL2)
9293 if (change_window_scaling_percent)
9295 SDLSetWindowScaling(setup.window_scaling_percent);
9299 else if (change_fullscreen)
9301 SDLSetWindowFullscreen(setup.fullscreen);
9303 /* set setup value according to successfully changed fullscreen mode */
9304 setup.fullscreen = video.fullscreen_enabled;
9310 if (change_fullscreen ||
9311 change_window_scaling_percent)
9313 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9315 /* save backbuffer content which gets lost when toggling fullscreen mode */
9316 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9318 if (change_window_scaling_percent)
9320 /* keep window mode, but change window scaling */
9321 video.fullscreen_enabled = TRUE; /* force new window scaling */
9324 /* toggle fullscreen */
9325 ChangeVideoModeIfNeeded(setup.fullscreen);
9327 /* set setup value according to successfully changed fullscreen mode */
9328 setup.fullscreen = video.fullscreen_enabled;
9330 /* restore backbuffer content from temporary backbuffer backup bitmap */
9331 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9333 FreeBitmap(tmp_backbuffer);
9335 /* update visible window/screen */
9336 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9340 static void JoinRectangles(int *x, int *y, int *width, int *height,
9341 int x2, int y2, int width2, int height2)
9343 // do not join with "off-screen" rectangle
9344 if (x2 == -1 || y2 == -1)
9349 *width = MAX(*width, width2);
9350 *height = MAX(*height, height2);
9353 void SetAnimStatus(int anim_status_new)
9355 if (anim_status_new == GAME_MODE_MAIN)
9356 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
9357 else if (anim_status_new == GAME_MODE_SCORES)
9358 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
9360 global.anim_status_next = anim_status_new;
9362 // directly set screen modes that are entered without fading
9363 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
9364 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
9365 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
9366 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
9367 global.anim_status = global.anim_status_next;
9370 void SetGameStatus(int game_status_new)
9372 if (game_status_new != game_status)
9373 game_status_last_screen = game_status;
9375 game_status = game_status_new;
9377 SetAnimStatus(game_status_new);
9380 void SetFontStatus(int game_status_new)
9382 static int last_game_status = -1;
9384 if (game_status_new != -1)
9386 // set game status for font use after storing last game status
9387 last_game_status = game_status;
9388 game_status = game_status_new;
9392 // reset game status after font use from last stored game status
9393 game_status = last_game_status;
9397 void ResetFontStatus(void)
9402 void SetLevelSetInfo(char *identifier, int level_nr)
9404 setString(&levelset.identifier, identifier);
9406 levelset.level_nr = level_nr;
9409 boolean CheckIfPlayfieldViewportHasChanged(void)
9411 // if game status has not changed, playfield viewport has not changed either
9412 if (game_status == game_status_last)
9415 // check if playfield viewport has changed with current game status
9416 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9417 int new_real_sx = vp_playfield->x;
9418 int new_real_sy = vp_playfield->y;
9419 int new_full_sxsize = vp_playfield->width;
9420 int new_full_sysize = vp_playfield->height;
9422 return (new_real_sx != REAL_SX ||
9423 new_real_sy != REAL_SY ||
9424 new_full_sxsize != FULL_SXSIZE ||
9425 new_full_sysize != FULL_SYSIZE);
9428 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged(void)
9430 return (CheckIfGlobalBorderHasChanged() ||
9431 CheckIfPlayfieldViewportHasChanged());
9434 void ChangeViewportPropertiesIfNeeded(void)
9436 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9437 FALSE : setup.small_game_graphics);
9438 int gfx_game_mode = game_status;
9439 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9441 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9442 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9443 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9444 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9445 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9446 int new_win_xsize = vp_window->width;
9447 int new_win_ysize = vp_window->height;
9448 int border_size = vp_playfield->border_size;
9449 int new_sx = vp_playfield->x + border_size;
9450 int new_sy = vp_playfield->y + border_size;
9451 int new_sxsize = vp_playfield->width - 2 * border_size;
9452 int new_sysize = vp_playfield->height - 2 * border_size;
9453 int new_real_sx = vp_playfield->x;
9454 int new_real_sy = vp_playfield->y;
9455 int new_full_sxsize = vp_playfield->width;
9456 int new_full_sysize = vp_playfield->height;
9457 int new_dx = vp_door_1->x;
9458 int new_dy = vp_door_1->y;
9459 int new_dxsize = vp_door_1->width;
9460 int new_dysize = vp_door_1->height;
9461 int new_vx = vp_door_2->x;
9462 int new_vy = vp_door_2->y;
9463 int new_vxsize = vp_door_2->width;
9464 int new_vysize = vp_door_2->height;
9465 int new_ex = vp_door_3->x;
9466 int new_ey = vp_door_3->y;
9467 int new_exsize = vp_door_3->width;
9468 int new_eysize = vp_door_3->height;
9469 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9470 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9471 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9472 int new_scr_fieldx = new_sxsize / tilesize;
9473 int new_scr_fieldy = new_sysize / tilesize;
9474 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9475 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9476 boolean init_gfx_buffers = FALSE;
9477 boolean init_video_buffer = FALSE;
9478 boolean init_gadgets_and_anims = FALSE;
9479 boolean init_em_graphics = FALSE;
9481 if (new_win_xsize != WIN_XSIZE ||
9482 new_win_ysize != WIN_YSIZE)
9484 WIN_XSIZE = new_win_xsize;
9485 WIN_YSIZE = new_win_ysize;
9487 init_video_buffer = TRUE;
9488 init_gfx_buffers = TRUE;
9489 init_gadgets_and_anims = TRUE;
9491 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9494 if (new_scr_fieldx != SCR_FIELDX ||
9495 new_scr_fieldy != SCR_FIELDY)
9497 /* this always toggles between MAIN and GAME when using small tile size */
9499 SCR_FIELDX = new_scr_fieldx;
9500 SCR_FIELDY = new_scr_fieldy;
9502 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9513 new_sxsize != SXSIZE ||
9514 new_sysize != SYSIZE ||
9515 new_dxsize != DXSIZE ||
9516 new_dysize != DYSIZE ||
9517 new_vxsize != VXSIZE ||
9518 new_vysize != VYSIZE ||
9519 new_exsize != EXSIZE ||
9520 new_eysize != EYSIZE ||
9521 new_real_sx != REAL_SX ||
9522 new_real_sy != REAL_SY ||
9523 new_full_sxsize != FULL_SXSIZE ||
9524 new_full_sysize != FULL_SYSIZE ||
9525 new_tilesize_var != TILESIZE_VAR
9528 // ------------------------------------------------------------------------
9529 // determine next fading area for changed viewport definitions
9530 // ------------------------------------------------------------------------
9532 // start with current playfield area (default fading area)
9535 FADE_SXSIZE = FULL_SXSIZE;
9536 FADE_SYSIZE = FULL_SYSIZE;
9538 // add new playfield area if position or size has changed
9539 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9540 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9542 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9543 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9546 // add current and new door 1 area if position or size has changed
9547 if (new_dx != DX || new_dy != DY ||
9548 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9550 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9551 DX, DY, DXSIZE, DYSIZE);
9552 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9553 new_dx, new_dy, new_dxsize, new_dysize);
9556 // add current and new door 2 area if position or size has changed
9557 if (new_dx != VX || new_dy != VY ||
9558 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9560 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9561 VX, VY, VXSIZE, VYSIZE);
9562 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9563 new_vx, new_vy, new_vxsize, new_vysize);
9566 // ------------------------------------------------------------------------
9567 // handle changed tile size
9568 // ------------------------------------------------------------------------
9570 if (new_tilesize_var != TILESIZE_VAR)
9572 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9574 // changing tile size invalidates scroll values of engine snapshots
9575 FreeEngineSnapshotSingle();
9577 // changing tile size requires update of graphic mapping for EM engine
9578 init_em_graphics = TRUE;
9589 SXSIZE = new_sxsize;
9590 SYSIZE = new_sysize;
9591 DXSIZE = new_dxsize;
9592 DYSIZE = new_dysize;
9593 VXSIZE = new_vxsize;
9594 VYSIZE = new_vysize;
9595 EXSIZE = new_exsize;
9596 EYSIZE = new_eysize;
9597 REAL_SX = new_real_sx;
9598 REAL_SY = new_real_sy;
9599 FULL_SXSIZE = new_full_sxsize;
9600 FULL_SYSIZE = new_full_sysize;
9601 TILESIZE_VAR = new_tilesize_var;
9603 init_gfx_buffers = TRUE;
9604 init_gadgets_and_anims = TRUE;
9606 // printf("::: viewports: init_gfx_buffers\n");
9607 // printf("::: viewports: init_gadgets_and_anims\n");
9610 if (init_gfx_buffers)
9612 // printf("::: init_gfx_buffers\n");
9614 SCR_FIELDX = new_scr_fieldx_buffers;
9615 SCR_FIELDY = new_scr_fieldy_buffers;
9619 SCR_FIELDX = new_scr_fieldx;
9620 SCR_FIELDY = new_scr_fieldy;
9622 SetDrawDeactivationMask(REDRAW_NONE);
9623 SetDrawBackgroundMask(REDRAW_FIELD);
9626 if (init_video_buffer)
9628 // printf("::: init_video_buffer\n");
9630 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9631 InitImageTextures();
9634 if (init_gadgets_and_anims)
9636 // printf("::: init_gadgets_and_anims\n");
9639 InitGlobalAnimations();
9642 if (init_em_graphics)
9644 InitGraphicInfo_EM();