From: Holger Schemel Date: Wed, 13 Dec 2017 07:39:30 +0000 (+0100) Subject: added tile selection cursor for playing MM levels with keyboard or joystick X-Git-Tag: 4.1.0.0~34 X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=commitdiff_plain;h=c9308ba3e7ddea2d7e44b4d98f0dfbb19e18f04f added tile selection cursor for playing MM levels with keyboard or joystick --- diff --git a/src/conf_gfx.c b/src/conf_gfx.c index 4be0ac31..8daac323 100644 --- a/src/conf_gfx.c +++ b/src/conf_gfx.c @@ -7127,6 +7127,11 @@ struct ConfigInfo image_config[] = { "global.busy.frames_per_line", "7" }, { "global.busy.delay", "2" }, + { "global.tile_cursor", "RocksMore.png" }, + { "global.tile_cursor.xpos", "10" }, + { "global.tile_cursor.ypos", "7" }, + { "global.tile_cursor.frames", "1" }, + { "background", UNDEFINED_FILENAME }, { "background.TITLE_INITIAL", UNDEFINED_FILENAME }, { "background.TITLE", UNDEFINED_FILENAME }, diff --git a/src/events.c b/src/events.c index 66486773..65b20da1 100644 --- a/src/events.c +++ b/src/events.c @@ -482,6 +482,9 @@ void HandleButtonEvent(ButtonEvent *event) event->x, event->y); #endif + // for any mouse button event, disable playfield tile cursor + SetTileCursorEnabled(FALSE); + #if defined(HAS_SCREEN_KEYBOARD) if (video.shifted_up) event->y += video.shifted_up_pos; @@ -1858,6 +1861,10 @@ void HandleKey(Key key, int key_status) if (key_status == KEY_PRESSED && key_action & KEY_ACTION) TapeTogglePause(TAPE_TOGGLE_MANUAL); } + + // for MM style levels, handle in-game keyboard input in HandleJoystick() + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + joy |= key_action; } } else @@ -2166,6 +2173,37 @@ void HandleEventActions() } } +static void HandleTileCursor(int dx, int dy, int button) +{ + if (!dx || !button) + ClearPlayerMouseAction(); + + if (!dx && !dy) + return; + + if (button) + { + SetPlayerMouseAction(tile_cursor.x, tile_cursor.y, + (dx < 0 ? MB_LEFTBUTTON : + dx > 0 ? MB_RIGHTBUTTON : MB_RELEASED)); + } + else + { + int old_xpos = tile_cursor.xpos; + int old_ypos = tile_cursor.ypos; + int new_xpos = old_xpos; + int new_ypos = old_ypos; + + if (IN_LEV_FIELD(old_xpos + dx, old_ypos)) + new_xpos = old_xpos + dx; + + if (IN_LEV_FIELD(old_xpos, old_ypos + dy)) + new_ypos = old_ypos + dy; + + SetTileCursorTargetXY(new_xpos, new_ypos); + } +} + static int HandleJoystickForAllPlayers() { int i; @@ -2201,9 +2239,13 @@ static int HandleJoystickForAllPlayers() void HandleJoystick() { + static unsigned int joytest_delay = 0; + static unsigned int joytest_delay_value = GADGET_FRAME_DELAY; + static int joytest_last = 0; int joystick = HandleJoystickForAllPlayers(); int keyboard = key_joystick_mapping; int joy = (joystick | keyboard); + int joytest = joystick; int left = joy & JOY_LEFT; int right = joy & JOY_RIGHT; int up = joy & JOY_UP; @@ -2219,6 +2261,31 @@ void HandleJoystick() return; } + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + { + // when playing MM style levels, also use delay for keyboard events + if (game_status == GAME_MODE_PLAYING) + joytest |= keyboard; + + // for any joystick or keyboard event, enable playfield tile cursor + if (dx || dy || button) + SetTileCursorEnabled(TRUE); + } + + if (joytest && !button && !DelayReached(&joytest_delay, joytest_delay_value)) + { + /* delay joystick/keyboard actions if axes/keys continually pressed */ + newbutton = dx = dy = 0; + } + else + { + /* first start with longer delay, then continue with shorter delay */ + joytest_delay_value = + (joytest != joytest_last ? GADGET_FRAME_DELAY_FIRST : GADGET_FRAME_DELAY); + } + + joytest_last = joytest; + switch (game_status) { case GAME_MODE_TITLE: @@ -2229,25 +2296,6 @@ void HandleJoystick() case GAME_MODE_INFO: case GAME_MODE_SCORES: { - static unsigned int joystickmove_delay = 0; - static unsigned int joystickmove_delay_value = GADGET_FRAME_DELAY; - static int joystick_last = 0; - - if (joystick && !button && - !DelayReached(&joystickmove_delay, joystickmove_delay_value)) - { - /* delay joystick actions if buttons/axes continually pressed */ - newbutton = dx = dy = 0; - } - else - { - /* start with longer delay, then continue with shorter delay */ - if (joystick != joystick_last) - joystickmove_delay_value = GADGET_FRAME_DELAY_FIRST; - else - joystickmove_delay_value = GADGET_FRAME_DELAY; - } - if (game_status == GAME_MODE_TITLE) HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); else if (game_status == GAME_MODE_MAIN) @@ -2263,8 +2311,6 @@ void HandleJoystick() else if (game_status == GAME_MODE_SCORES) HandleHallOfFame(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK); - joystick_last = joystick; - break; } @@ -2285,6 +2331,9 @@ void HandleJoystick() TapeTogglePause(TAPE_TOGGLE_MANUAL); } + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + HandleTileCursor(dx, dy, button); + break; default: diff --git a/src/game_mm/mm_game.c b/src/game_mm/mm_game.c index aff897b1..ec206faf 100644 --- a/src/game_mm/mm_game.c +++ b/src/game_mm/mm_game.c @@ -744,6 +744,9 @@ void InitGameActions_MM() if (game_mm.kettles_still_needed == 0) CheckExitMM(); + + SetTileCursorXY(laser.start_edge.x, laser.start_edge.y); + SetTileCursorActive(TRUE); } void AddLaserEdge(int lx, int ly) @@ -1965,8 +1968,12 @@ boolean HitLaserDestination(int element, int hit_mask) AddDamagedField(ELX, ELY); if (game_mm.lights_still_needed == 0) + { game_mm.level_solved = TRUE; + SetTileCursorActive(FALSE); + } + return TRUE; } @@ -2474,6 +2481,8 @@ static void Explode_MM(int x, int y, int phase, int mode) game_mm.game_over = TRUE; game_mm.game_over_cause = GAME_OVER_BOMB; + SetTileCursorActive(FALSE); + laser.overloaded = FALSE; } else if (IS_MCDUFFIN(Store[x][y])) @@ -3155,6 +3164,8 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode) game_mm.game_over = TRUE; game_mm.game_over_cause = GAME_OVER_NO_ENERGY; + SetTileCursorActive(FALSE); + #if 0 if (Request("Out of magic energy ! Play it again ?", REQ_ASK | REQ_STAY_CLOSED)) @@ -3285,6 +3296,8 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode) game_mm.game_over = TRUE; game_mm.game_over_cause = GAME_OVER_OVERLOADED; + SetTileCursorActive(FALSE); + #if 0 if (Request("Magic spell hit Mc Duffin ! Play it again ?", REQ_ASK | REQ_STAY_CLOSED)) diff --git a/src/init.c b/src/init.c index ff9f0344..dc929129 100644 --- a/src/init.c +++ b/src/init.c @@ -5431,6 +5431,7 @@ void InitGfx() InitGfxDrawBusyAnimFunction(DrawInitAnim); InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations); InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget); + InitGfxDrawTileCursorFunction(DrawTileCursor); gfx.fade_border_source_status = global.border_status; gfx.fade_border_target_status = global.border_status; @@ -6008,6 +6009,7 @@ void OpenAll() InitVideoDisplay(); InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen); + InitTileCursorInfo(); InitOverlayInfo(); print_timestamp_time("[init video stuff]"); diff --git a/src/libgame/sdl.c b/src/libgame/sdl.c index 9d2dc17c..34c40044 100644 --- a/src/libgame/sdl.c +++ b/src/libgame/sdl.c @@ -62,6 +62,10 @@ static void FinalizeScreen(int draw_target) // copy global animations to render target buffer, if defined (above border) if (gfx.draw_global_anim_function != NULL) gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2); + + // copy tile selection cursor to render target buffer, if defined (above all) + if (gfx.draw_tile_cursor_function != NULL) + gfx.draw_tile_cursor_function(draw_target); } static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay) diff --git a/src/libgame/system.c b/src/libgame/system.c index 6c2e9684..dea7258d 100644 --- a/src/libgame/system.c +++ b/src/libgame/system.c @@ -33,6 +33,7 @@ struct OptionInfo options; struct VideoSystemInfo video; struct AudioSystemInfo audio; struct GfxInfo gfx; +struct TileCursorInfo tile_cursor; struct OverlayInfo overlay; struct ArtworkInfo artwork; struct JoystickInfo joystick; @@ -286,6 +287,11 @@ void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int)) gfx.draw_global_border_function = draw_global_border_function; } +void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int)) +{ + gfx.draw_tile_cursor_function = draw_tile_cursor_function; +} + void InitGfxCustomArtworkInfo() { gfx.override_level_graphics = FALSE; @@ -300,6 +306,19 @@ void InitGfxOtherSettings() gfx.cursor_mode = CURSOR_DEFAULT; } +void InitTileCursorInfo() +{ + tile_cursor.enabled = FALSE; + tile_cursor.active = FALSE; + + tile_cursor.xpos = 0; + tile_cursor.ypos = 0; + tile_cursor.x = 0; + tile_cursor.y = 0; + tile_cursor.target_x = 0; + tile_cursor.target_y = 0; +} + void InitOverlayInfo() { overlay.enabled = FALSE; @@ -311,6 +330,37 @@ void InitOverlayInfo() #endif } +void SetTileCursorEnabled(boolean enabled) +{ + tile_cursor.enabled = enabled; +} + +void SetTileCursorActive(boolean active) +{ + tile_cursor.active = active; +} + +void SetTileCursorTargetXY(int x, int y) +{ + // delayed placement of tile selection cursor at target position + // (tile cursor will be moved to target position step by step) + + tile_cursor.xpos = x; + tile_cursor.ypos = y; + tile_cursor.target_x = gfx.sx + x * gfx.game_tile_size; + tile_cursor.target_y = gfx.sy + y * gfx.game_tile_size; +} + +void SetTileCursorXY(int x, int y) +{ + // immediate placement of tile selection cursor at target position + + SetTileCursorTargetXY(x, y); + + tile_cursor.x = tile_cursor.target_x; + tile_cursor.y = tile_cursor.target_y; +} + void SetOverlayEnabled(boolean enabled) { overlay.enabled = enabled; diff --git a/src/libgame/system.h b/src/libgame/system.h index 871fcd89..a2226a78 100644 --- a/src/libgame/system.h +++ b/src/libgame/system.h @@ -949,10 +949,21 @@ struct GfxInfo void (*draw_busy_anim_function)(void); void (*draw_global_anim_function)(int, int); void (*draw_global_border_function)(int); + void (*draw_tile_cursor_function)(int); int cursor_mode; }; +struct TileCursorInfo +{ + boolean enabled; /* tile cursor generally enabled or disabled */ + boolean active; /* tile cursor activated (depending on game) */ + + int xpos, ypos; /* tile cursor level playfield position */ + int x, y; /* tile cursor current screen position */ + int target_x, target_y; /* tile cursor target screen position */ +}; + struct OverlayInfo { boolean enabled; /* overlay generally enabled or disabled */ @@ -1457,6 +1468,7 @@ extern struct OptionInfo options; extern struct VideoSystemInfo video; extern struct AudioSystemInfo audio; extern struct GfxInfo gfx; +extern struct TileCursorInfo tile_cursor; extern struct OverlayInfo overlay; extern struct AnimInfo anim; extern struct ArtworkInfo artwork; @@ -1511,9 +1523,15 @@ void InitGfxClipRegion(boolean, int, int, int, int); void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void)); void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int)); void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int)); +void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int)); void InitGfxCustomArtworkInfo(); void InitGfxOtherSettings(); +void InitTileCursorInfo(); void InitOverlayInfo(); +void SetTileCursorEnabled(boolean); +void SetTileCursorActive(boolean); +void SetTileCursorTargetXY(int, int); +void SetTileCursorXY(int, int); void SetOverlayEnabled(boolean); void SetOverlayActive(boolean); boolean GetOverlayActive(); diff --git a/src/tools.c b/src/tools.c index 55c757af..3c301a39 100644 --- a/src/tools.c +++ b/src/tools.c @@ -635,6 +635,61 @@ void DrawMaskedBorderToTarget(int draw_target) } } +void DrawTileCursor(int draw_target) +{ + Bitmap *fade_bitmap; + Bitmap *src_bitmap; + int src_x, src_y; + int dst_x, dst_y; + int graphic = IMG_GLOBAL_TILE_CURSOR; + int frame = 0; + int tilesize = TILESIZE_VAR; + int width = tilesize; + int height = tilesize; + + if (game_status != GAME_MODE_PLAYING) + return; + + if (!tile_cursor.enabled || + !tile_cursor.active) + return; + + if (tile_cursor.x != tile_cursor.target_x || + tile_cursor.y != tile_cursor.target_y) + { + int step = TILESIZE_VAR / (GADGET_FRAME_DELAY / video.frame_delay_value); + int dx = tile_cursor.target_x - tile_cursor.x; + int dy = tile_cursor.target_y - tile_cursor.y; + + if (ABS(dx) < step) + tile_cursor.x = tile_cursor.target_x; + else + tile_cursor.x += SIGN(dx) * step; + + if (ABS(dy) < step) + tile_cursor.y = tile_cursor.target_y; + else + tile_cursor.y += SIGN(dy) * step; + } + + dst_x = tile_cursor.x; + dst_y = tile_cursor.y; + + frame = getGraphicAnimationFrame(graphic, -1); + + getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y); + + fade_bitmap = + (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source : + draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL); + + if (draw_target == DRAW_TO_SCREEN) + BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y); + else + BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height, + dst_x, dst_y); +} + void BlitScreenToBitmap_RND(Bitmap *target_bitmap) { int fx = getFieldbufferOffsetX_RND(); @@ -1005,6 +1060,7 @@ void FadeOut(int fade_mask) SetScreenStates_BeforeFadingOut(); + SetTileCursorActive(FALSE); SetOverlayActive(FALSE); #if 0 diff --git a/src/tools.h b/src/tools.h index 37c67dd4..5d9bdcce 100644 --- a/src/tools.h +++ b/src/tools.h @@ -82,6 +82,7 @@ void DrawMaskedBorder_DOOR_3(); void DrawMaskedBorder_ALL(); void DrawMaskedBorder(int); void DrawMaskedBorderToTarget(int); +void DrawTileCursor(int); void SetDrawtoField(int); void RedrawPlayfield();