diff --git a/stardew-access/Features/ReadTile.cs b/stardew-access/Features/ReadTile.cs index 183c868..2fcabcd 100644 --- a/stardew-access/Features/ReadTile.cs +++ b/stardew-access/Features/ReadTile.cs @@ -34,7 +34,7 @@ namespace stardew_access.Game { if (!manuallyTriggered && prevTile != gt) { - if(MainClass.screenReader!=null) + if (MainClass.screenReader != null) MainClass.screenReader.PrevTextTile = " "; } @@ -69,9 +69,9 @@ namespace stardew_access.Game if (terrain != null) toSpeak = terrain; } - else if ( Game1.currentLocation.getLargeTerrainFeatureAt(x, y) != null ) + else if (Game1.currentLocation.getLargeTerrainFeatureAt(x, y) != null) { - Bush bush = (Bush) Game1.currentLocation.getLargeTerrainFeatureAt(x, y); + Bush bush = (Bush)Game1.currentLocation.getLargeTerrainFeatureAt(x, y); int size = bush.size; #region Check if bush is harvestable or not @@ -108,9 +108,9 @@ namespace stardew_access.Game } #endregion - if(bush.townBush) + if (bush.townBush) toSpeak = $"{toSpeak} Town Bush"; - else if(bush.greenhouseBush) + else if (bush.greenhouseBush) toSpeak = $"{toSpeak} Greenhouse Bush"; else toSpeak = $"{toSpeak} Bush"; @@ -191,7 +191,7 @@ namespace stardew_access.Game _ => null, }; - if (communityCenter.shouldNoteAppearInArea(CommunityCenter.getAreaNumberFromName(name))) + if (name != null && communityCenter.shouldNoteAppearInArea(CommunityCenter.getAreaNumberFromName(name))) return $"{name} bundle"; else return null; @@ -199,7 +199,7 @@ namespace stardew_access.Game public static bool isCollidingAtTile(int x, int y) { - Rectangle rect = new Rectangle(x * 64 + 1,y * 64 + 1, 62, 62); + Rectangle rect = new Rectangle(x * 64 + 1, y * 64 + 1, 62, 62); if (Game1.currentLocation.isCollidingPosition(rect, Game1.viewport, true, 0, glider: false, Game1.player, pathfinding: true)) { @@ -219,15 +219,15 @@ namespace stardew_access.Game List? farmAnimals = null; - if(location is Farm) + if (location is Farm) farmAnimals = (location as Farm).getAllFarmAnimals(); - else if(location is AnimalHouse) + else if (location is AnimalHouse) farmAnimals = (location as AnimalHouse).animals.Values.ToList(); if (farmAnimals == null || farmAnimals.Count <= 0) return null; - for(int i = 0; i < farmAnimals.Count; i++) + for (int i = 0; i < farmAnimals.Count; i++) { int fx = farmAnimals[i].getTileX(); int fy = farmAnimals[i].getTileY(); @@ -255,7 +255,7 @@ namespace stardew_access.Game /// /// Item1: This is the category of the tile. Default to Furnitures. ///
Item2: This is the name of the tile. Default to null if the tile tile has nothing on it.
- public static (CATEGORY?,string?) getTileInfo(int x, int y) + public static (CATEGORY?, string?) getTileInfo(int x, int y) { int? index = null; @@ -266,7 +266,7 @@ namespace stardew_access.Game MainClass.monitor.Log(index.ToString(), LogLevel.Debug); */ - if(Game1.currentLocation is Farm) + if (Game1.currentLocation is Farm) { Building building = (Game1.currentLocation as Farm).getBuildingAt(new Vector2(x, y)); if (building != null) @@ -348,7 +348,7 @@ namespace stardew_access.Game toReturn = "Fertilized " + toReturn; } } - else if(terrain.Get() is GiantCrop) + else if (terrain.Get() is GiantCrop) { int whichCrop = (terrain.Get() as GiantCrop).which.Value; switch (whichCrop) @@ -413,7 +413,7 @@ namespace stardew_access.Game { toReturn = "Leaf"; } - + return toReturn; } @@ -426,13 +426,13 @@ namespace stardew_access.Game if (stage == 0) toReturn = $"{toReturn} seed"; - else if(stage == 1) + else if (stage == 1) toReturn = $"{toReturn} sprout"; - else if(stage == 2) + else if (stage == 2) toReturn = $"{toReturn} sapling"; - else if(stage == 3) + else if (stage == 3) toReturn = $"{toReturn} bush"; - else if(stage >= 4) + else if (stage >= 4) toReturn = $"{toReturn} tree"; if (fruitTree.fruitsOnTree.Value > 0) @@ -460,7 +460,7 @@ namespace stardew_access.Game return "Mushroom Tree"; } - + if (treeType <= 3) seedName = Game1.objectInformation[308 + treeType].Split('/')[0]; else if (treeType == 8) @@ -486,11 +486,11 @@ namespace stardew_access.Game if (treeStage == 1) treeName = $"{treeName} sprout"; - else if(treeStage == 2) + else if (treeStage == 2) treeName = $"{treeName} sapling"; - else if(treeStage == 3 || treeStage == 4) + else if (treeStage == 3 || treeStage == 4) treeName = $"{treeName} bush"; - else if(treeStage >= 5) + else if (treeStage >= 5) treeName = $"{treeName} tree"; return treeName; @@ -629,7 +629,7 @@ namespace stardew_access.Game } } - if(obj is Chest) + if (obj is Chest) { Chest chest = (Chest)obj; toReturn = chest.DisplayName; @@ -645,15 +645,15 @@ namespace stardew_access.Game if (Game1.currentLocation is Mine or MineShaft) { int? index = null; - - if(Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y]!=null) + + if (Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y] != null) index = Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y].TileIndex; if (index == 173 || index == 174) return true; } } - catch (Exception) {} + catch (Exception) { } return false; } @@ -703,9 +703,9 @@ namespace stardew_access.Game Point tilePoint = new Point(x, y); List> doorList = Game1.currentLocation.doors.ToList(); - for (int i=0; i < doorList.Count; i++) - { - for(int j = 0; j< doorList[i].Keys.Count; j++) + for (int i = 0; i < doorList.Count; i++) + { + for (int j = 0; j < doorList[i].Keys.Count; j++) { if (doorList[i].Keys.Contains(tilePoint)) return true; @@ -718,7 +718,7 @@ namespace stardew_access.Game public static string? getResourceClumpAtTile(int x, int y) { - for(int i = 0; i < Game1.currentLocation.resourceClumps.Count; i++) + for (int i = 0; i < Game1.currentLocation.resourceClumps.Count; i++) { if (Game1.currentLocation.resourceClumps[i].occupiesTile(x, y)) { diff --git a/stardew-access/HarmonyPatches.cs b/stardew-access/HarmonyPatches.cs index 0f0633f..920489b 100644 --- a/stardew-access/HarmonyPatches.cs +++ b/stardew-access/HarmonyPatches.cs @@ -95,6 +95,11 @@ namespace stardew_access original: AccessTools.Method(typeof(SocialPage), nameof(SocialPage.draw), new Type[] { typeof(SpriteBatch) }), postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.SocialPagePatch)) ); + + harmony.Patch( + original: AccessTools.Method(typeof(JunimoNoteMenu), nameof(JunimoNoteMenu.draw), new Type[] { typeof(SpriteBatch) }), + postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.JunimoNoteMenuPatch)) + ); #endregion #region Menu Patches diff --git a/stardew-access/Patches/DialoguePatches.cs b/stardew-access/Patches/DialoguePatches.cs index dd33f85..322ca7d 100644 --- a/stardew-access/Patches/DialoguePatches.cs +++ b/stardew-access/Patches/DialoguePatches.cs @@ -137,23 +137,29 @@ namespace stardew_access.Patches if (Game1.activeClickableMenu is GameMenu && (Game1.activeClickableMenu as GameMenu).GetCurrentPage() is ExitPage) return; + if (Game1.activeClickableMenu is GameMenu && (Game1.activeClickableMenu as GameMenu).GetCurrentPage() is SocialPage) + return; + if (Game1.activeClickableMenu is ItemGrabMenu) return; if (Game1.activeClickableMenu is ShopMenu) return; - + if (Game1.activeClickableMenu is ConfirmationDialog) return; + + if (Game1.activeClickableMenu is JunimoNoteMenu) + return; #endregion StringBuilder toSpeak = new StringBuilder(" "); #region Add item count before title - if(hoveredItem != null && hoveredItem.HasBeenInInventory) + if (hoveredItem != null && hoveredItem.HasBeenInInventory) { int count = hoveredItem.Stack; - if(count > 1) + if (count > 1) toSpeak.Append($"{count} "); } #endregion @@ -164,7 +170,7 @@ namespace stardew_access.Patches #endregion #region Add quality of item - if (hoveredItem is StardewValley.Object && (hoveredItem as StardewValley.Object).quality>0) + if (hoveredItem is StardewValley.Object && (hoveredItem as StardewValley.Object).quality > 0) { int quality = (hoveredItem as StardewValley.Object).quality; if (quality == 1) diff --git a/stardew-access/Patches/GameMenuPatches.cs b/stardew-access/Patches/GameMenuPatches.cs index 6f9eca8..2b0814a 100644 --- a/stardew-access/Patches/GameMenuPatches.cs +++ b/stardew-access/Patches/GameMenuPatches.cs @@ -1,6 +1,7 @@  using StardewModdingAPI; using StardewValley; +using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Objects; @@ -18,8 +19,283 @@ namespace stardew_access.Patches internal static string optionsPageQueryKey = ""; internal static string shopMenuQueryKey = ""; internal static string socialPageQuery = ""; + internal static string profilePageQuery = ""; + internal static string junimoNoteMenuQuery = ""; internal static int currentSelectedCraftingRecipe = -1; internal static bool isSelectingRecipe = false; + internal static bool isUsingCustomButtons = false; + internal static int currentIngredientListItem = -1, currentIngredientInputSlot = -1, currentInventorySlot = -1; + + internal static void JunimoNoteMenuPatch(JunimoNoteMenu __instance, bool ___specificBundlePage, int ___whichArea, Bundle ___currentPageBundle) + { + try + { + int x = Game1.getMouseX(), y = Game1.getMouseY(); // Mouse x and y position + if (!___specificBundlePage) + { + currentIngredientListItem = -1; + isUsingCustomButtons = false; + + string areaName = __instance.scrambledText ? CommunityCenter.getAreaEnglishDisplayNameFromNumber(___whichArea) : CommunityCenter.getAreaDisplayNameFromNumber(___whichArea); + if (__instance.scrambledText) + { + string toSpeak = "Scrambled Text"; + if (junimoNoteMenuQuery != toSpeak) + { + junimoNoteMenuQuery = toSpeak; + MainClass.screenReader.Say(toSpeak, true); + } + return; + } + for (int i = 0; i < __instance.bundles.Count; i++) + { + if (__instance.bundles[i].containsPoint(x, y)) + { + string toSpeak = $"{__instance.bundles[i].name} bundle"; + if (junimoNoteMenuQuery != toSpeak) + { + junimoNoteMenuQuery = toSpeak; + MainClass.screenReader.Say(toSpeak, true); + } + return; + } + } + if (__instance.presentButton != null && __instance.presentButton.containsPoint(x, y)) + { + string toSpeak = "Present Button"; + if (junimoNoteMenuQuery != toSpeak) + { + junimoNoteMenuQuery = toSpeak; + MainClass.screenReader.Say(toSpeak, true); + } + return; + } + if (__instance.fromGameMenu) + { + if (__instance.areaNextButton.visible && __instance.areaNextButton.containsPoint(x, y)) + { + string toSpeak = "Next Area Button"; + if (junimoNoteMenuQuery != toSpeak) + { + junimoNoteMenuQuery = toSpeak; + MainClass.screenReader.Say(toSpeak, true); + } + return; + } + if (__instance.areaBackButton.visible && __instance.areaBackButton.containsPoint(x, y)) + { + string toSpeak = "Previous Area Button"; + if (junimoNoteMenuQuery != toSpeak) + { + junimoNoteMenuQuery = toSpeak; + MainClass.screenReader.Say(toSpeak, true); + } + return; + } + } + } + else + { + bool isIPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.I); // For the ingredients + bool isCPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.C); // For the items in inventory + bool isPPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.P); // For the Purchase Button + bool isVPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.V); // For the ingredient input slots + bool isBackPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Back); // For the back button + bool isLeftShiftPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift); + + if (isIPressed && !isUsingCustomButtons) + { + JunimoNoteCustomButtons(__instance, ___currentPageBundle, 0, isLeftShiftPressed); + } + else if (isVPressed && !isUsingCustomButtons) + { + JunimoNoteCustomButtons(__instance, ___currentPageBundle, 1, isLeftShiftPressed); + } + else if (isCPressed && !isUsingCustomButtons) + { + JunimoNoteCustomButtons(__instance, ___currentPageBundle, 2, isLeftShiftPressed); + } + else if (isBackPressed && __instance.backButton != null && !__instance.backButton.containsPoint(x, y)) + { + __instance.backButton.snapMouseCursorToCenter(); + MainClass.screenReader.Say("Back Button", true); + } + else if (isPPressed && __instance.purchaseButton != null && !__instance.purchaseButton.containsPoint(x, y)) + { + __instance.purchaseButton.snapMouseCursorToCenter(); + MainClass.screenReader.Say("Purchase Button", true); + } + } + string reward = __instance.getRewardNameForArea(___whichArea); + } + catch (Exception e) + { + MainClass.monitor.Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error); + } + } + + private static async void JunimoNoteCustomButtons(JunimoNoteMenu __instance, Bundle ___currentPageBundle, int signal, bool isLeftShiftPressed = false) + { + isUsingCustomButtons = true; + try + { + + switch (signal) + { + case 0: // For ingredient list + { + if (___currentPageBundle.ingredients.Count >= 0) + { + currentIngredientListItem = currentIngredientListItem + (isLeftShiftPressed ? -1 : 1); + if (currentIngredientListItem >= ___currentPageBundle.ingredients.Count) + if (isLeftShiftPressed) + currentIngredientListItem = ___currentPageBundle.ingredients.Count - 1; + else + currentIngredientListItem = 0; + + if (currentIngredientListItem < 0) + if (isLeftShiftPressed) + currentIngredientListItem = ___currentPageBundle.ingredients.Count - 1; + else + currentIngredientListItem = 0; + + ClickableTextureComponent c = __instance.ingredientList[currentIngredientListItem]; + BundleIngredientDescription ingredient = ___currentPageBundle.ingredients[currentIngredientListItem]; + + Item item = new StardewValley.Object(ingredient.index, ingredient.stack, isRecipe: false, -1, ingredient.quality); + bool completed = false; + if (___currentPageBundle != null && ___currentPageBundle.ingredients != null && currentIngredientListItem < ___currentPageBundle.ingredients.Count && ___currentPageBundle.ingredients[currentIngredientListItem].completed) + { + completed = true; + } + + string toSpeak = item.DisplayName; + + if (!completed) + { + int quality = ingredient.quality; + if (quality == 1) + { + toSpeak = $"Silver quality {toSpeak}"; + } + else if (quality == 2 || quality == 3) + { + toSpeak = $"Gold quality {toSpeak}"; + } + else if (quality >= 4) + { + toSpeak = $"Iridium quality {toSpeak}"; + } + + toSpeak = $"{ingredient.stack} {toSpeak}"; + } + + if (completed) + toSpeak = $"Completed {toSpeak}"; + + c.snapMouseCursorToCenter(); + MainClass.screenReader.Say(toSpeak, true); + } + } + break; + case 1: // For input slot list + { + if (__instance.ingredientSlots.Count >= 0) + { + currentIngredientInputSlot = currentIngredientInputSlot + (isLeftShiftPressed ? -1 : 1); + if (currentIngredientInputSlot >= __instance.ingredientSlots.Count) + if (isLeftShiftPressed) + currentIngredientInputSlot = __instance.ingredientSlots.Count - 1; + else + currentIngredientInputSlot = 0; + + if (currentIngredientInputSlot < 0) + if (isLeftShiftPressed) + currentIngredientInputSlot = __instance.ingredientSlots.Count - 1; + else + currentIngredientInputSlot = 0; + + ClickableTextureComponent c = __instance.ingredientSlots[currentIngredientInputSlot]; + Item item = c.item; + string toSpeak; + + if (item == null) + { + toSpeak = $"Input Slot {currentIngredientInputSlot + 1}"; + } + else + { + toSpeak = item.DisplayName; + } + + c.snapMouseCursorToCenter(); + MainClass.screenReader.Say(toSpeak, true); + } + } + break; + case 2: // For inventory slots + { + if (__instance.inventory != null && __instance.inventory.inventory.Count >= 0) + { + int prevSlotIndex = currentInventorySlot; + currentInventorySlot = currentInventorySlot + (isLeftShiftPressed ? -1 : 1); + if (currentInventorySlot >= __instance.inventory.inventory.Count) + if (isLeftShiftPressed) + currentInventorySlot = __instance.inventory.inventory.Count - 1; + else + currentInventorySlot = 0; + + if (currentInventorySlot < 0) + if (isLeftShiftPressed) + currentInventorySlot = __instance.inventory.inventory.Count - 1; + else + currentInventorySlot = 0; + + Item item = __instance.inventory.actualInventory[currentInventorySlot]; + ClickableComponent c = __instance.inventory.inventory[currentInventorySlot]; + string toSpeak; + if (item != null) + { + toSpeak = item.DisplayName; + + if ((item as StardewValley.Object) != null) + { + int quality = (item as StardewValley.Object).quality; + if (quality == 1) + { + toSpeak = $"Silver quality {toSpeak}"; + } + else if (quality == 2 || quality == 3) + { + toSpeak = $"Gold quality {toSpeak}"; + } + else if (quality >= 4) + { + toSpeak = $"Iridium quality {toSpeak}"; + } + } + toSpeak = $"{item.Stack} {toSpeak}"; + + } + else + { + toSpeak = "Empty Slot"; + } + c.snapMouseCursorToCenter(); + MainClass.screenReader.Say(toSpeak, true); + } + } + break; + } + } + catch (Exception e) + { + MainClass.monitor.Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error); + } + + await Task.Delay(200); + isUsingCustomButtons = false; + } internal static void SocialPagePatch(SocialPage __instance, List ___sprites, int ___slotPosition, List ___kidsNames) { @@ -99,6 +375,7 @@ namespace stardew_access.Patches socialPageQuery = toSpeak; MainClass.screenReader.Say(toSpeak, true); } + return; } #endregion } @@ -143,6 +420,7 @@ namespace stardew_access.Patches socialPageQuery = toSpeak; MainClass.screenReader.Say(toSpeak, true); } + return; } } diff --git a/stardew-access/Patches/MenuPatches.cs b/stardew-access/Patches/MenuPatches.cs index e84f01c..4f7e803 100644 --- a/stardew-access/Patches/MenuPatches.cs +++ b/stardew-access/Patches/MenuPatches.cs @@ -302,9 +302,30 @@ namespace stardew_access.Patches GameMenuPatches.inventoryPageQueryKey = ""; GameMenuPatches.exitPageQueryKey = ""; GameMenuPatches.optionsPageQueryKey = ""; + GameMenuPatches.socialPageQuery = ""; GameMenuPatches.currentSelectedCraftingRecipe = -1; GameMenuPatches.isSelectingRecipe = false; } + + if (Game1.activeClickableMenu is JunimoNoteMenu) + { + GameMenuPatches.currentIngredientListItem = -1; + GameMenuPatches.currentIngredientInputSlot = -1; + GameMenuPatches.currentInventorySlot = -1; + GameMenuPatches.junimoNoteMenuQuery = ""; + } + + if (Game1.activeClickableMenu is ShopMenu) + { + GameMenuPatches.shopMenuQueryKey = ""; + } + + if (Game1.activeClickableMenu is ItemGrabMenu) + { + GameMenuPatches.itemGrabMenuQueryKey = ""; + } + + GameMenuPatches.hoveredItemQueryKey = ""; } catch (Exception e) { diff --git a/stardew-access/manifest.json b/stardew-access/manifest.json index a9dcc84..117f409 100644 --- a/stardew-access/manifest.json +++ b/stardew-access/manifest.json @@ -1,7 +1,7 @@ { "Name": "Stardew Access", "Author": "Mohammad Shoaib", - "Version": "1.0.19-beta", + "Version": "1.0.20-beta", "Description": "An accessibility mod with screen reader support!", "UniqueID": "shoaib.stardewaccess", "EntryDll": "stardew-access.dll",