Merge remote-tracking branch 'sda/master' into update
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,7 +3,12 @@
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
*.dll
|
||||
stardew-access/assets/custom-tiles.json
|
||||
|
||||
.vscode/*
|
||||
.git-old/
|
||||
bin/
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
|
@@ -16,13 +16,13 @@ namespace stardew_access.ScreenReader
|
||||
/// <param name="center">The starting point.</param>
|
||||
/// <param name="limit">The limiting factor or simply radius of the search area.</param>
|
||||
/// <returns>A dictionary with all the detected tiles along with the name of the object on it and it's category.</returns>
|
||||
public Dictionary<Vector2, (string, string)> SearchNearbyTiles(Vector2 center, int limit)
|
||||
public Dictionary<Vector2, (string name, string category)> SearchNearbyTiles(Vector2 center, int limit)
|
||||
{
|
||||
/*
|
||||
* How to use the Dictionary to get the name and category of a tile:-
|
||||
*
|
||||
* string? objectName = detectedTiles.GetValueOrDefault(center).Item1;
|
||||
* string? objectCategory = detectedTiles.GetValueOrDefault(center).Item2;
|
||||
* string tileName = detectedTiles.GetValueOrDefault(tilePosition).name;
|
||||
* string tileCategory = detectedTiles.GetValueOrDefault(tilePosition).category;
|
||||
*
|
||||
* Here detectedTiles is the Dictionary returned by this method
|
||||
*/
|
||||
@@ -30,14 +30,32 @@ namespace stardew_access.ScreenReader
|
||||
return new Radar().SearchNearbyTiles(center, limit, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search the entire location using Breadth First Search algorithm(BFS).
|
||||
/// </summary>
|
||||
/// <returns>A dictionary with all the detected tiles along with the name of the object on it and it's category.</returns>
|
||||
public Dictionary<Vector2, (string name, string category)> SearchLocation()
|
||||
{
|
||||
/*
|
||||
* How to use the Dictionary to get the name and category of a tile:-
|
||||
*
|
||||
* string tileName = detectedTiles.GetValueOrDefault(tilePosition).name;
|
||||
* string tileCategory = detectedTiles.GetValueOrDefault(tilePosition).category;
|
||||
*
|
||||
* Here detectedTiles is the Dictionary returned by this method
|
||||
*/
|
||||
|
||||
return new Radar().SearchLocation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the tile for any object
|
||||
/// </summary>
|
||||
/// <param name="tile">The tile where we want to check the name and category of object if any</param>
|
||||
/// <returns>Name of the object as the first item (Item1) and category as the second item (Item2). Returns null if no object found.</returns>
|
||||
public (string?, string?) GetNameWithCategoryNameAtTile(Vector2 tile)
|
||||
/// <returns>Name of the object as the first item (name) and category as the second item (category). Returns null if no object found.</returns>
|
||||
public (string? name, string? category) GetNameWithCategoryNameAtTile(Vector2 tile)
|
||||
{
|
||||
return ReadTile.getNameWithCategoryNameAtTile(tile);
|
||||
return TileInfo.getNameWithCategoryNameAtTile(tile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,7 +65,7 @@ namespace stardew_access.ScreenReader
|
||||
/// <returns>Name of the object. Returns null if no object found.</returns>
|
||||
public string? GetNameAtTile(Vector2 tile)
|
||||
{
|
||||
return ReadTile.getNameAtTile(tile);
|
||||
return TileInfo.getNameAtTile(tile);
|
||||
}
|
||||
|
||||
/// <summary>Speaks the text via the loaded screen reader (if any).</summary>
|
||||
@@ -55,10 +73,10 @@ namespace stardew_access.ScreenReader
|
||||
/// <param name="interrupt">Whether to skip the currently speaking text or not.</param>
|
||||
public void Say(String text, Boolean interrupt)
|
||||
{
|
||||
if (MainClass.GetScreenReader() == null)
|
||||
if (MainClass.ScreenReader == null)
|
||||
return;
|
||||
|
||||
MainClass.GetScreenReader().Say(text, interrupt);
|
||||
MainClass.ScreenReader.Say(text, interrupt);
|
||||
}
|
||||
|
||||
/// <summary>Speaks the text via the loaded screen reader (if any).
|
||||
@@ -67,10 +85,10 @@ namespace stardew_access.ScreenReader
|
||||
/// <param name="interrupt">Whether to skip the currently speaking text or not.</param>
|
||||
public void SayWithChecker(String text, Boolean interrupt)
|
||||
{
|
||||
if (MainClass.GetScreenReader() == null)
|
||||
if (MainClass.ScreenReader == null)
|
||||
return;
|
||||
|
||||
MainClass.GetScreenReader().SayWithChecker(text, interrupt);
|
||||
MainClass.ScreenReader.SayWithChecker(text, interrupt);
|
||||
}
|
||||
|
||||
/// <summary>Speaks the text via the loaded screen reader (if any).
|
||||
@@ -80,10 +98,10 @@ namespace stardew_access.ScreenReader
|
||||
/// <param name="interrupt">Whether to skip the currently speaking text or not.</param>
|
||||
public void SayWithMenuChecker(String text, Boolean interrupt)
|
||||
{
|
||||
if (MainClass.GetScreenReader() == null)
|
||||
if (MainClass.ScreenReader == null)
|
||||
return;
|
||||
|
||||
MainClass.GetScreenReader().SayWithMenuChecker(text, interrupt);
|
||||
MainClass.ScreenReader.SayWithMenuChecker(text, interrupt);
|
||||
}
|
||||
|
||||
/// <summary>Speaks the text via the loaded screen reader (if any).
|
||||
@@ -93,10 +111,10 @@ namespace stardew_access.ScreenReader
|
||||
/// <param name="interrupt">Whether to skip the currently speaking text or not.</param>
|
||||
public void SayWithChatChecker(String text, Boolean interrupt)
|
||||
{
|
||||
if (MainClass.GetScreenReader() == null)
|
||||
if (MainClass.ScreenReader == null)
|
||||
return;
|
||||
|
||||
MainClass.GetScreenReader().SayWithChatChecker(text, interrupt);
|
||||
MainClass.ScreenReader.SayWithChatChecker(text, interrupt);
|
||||
}
|
||||
|
||||
/// <summary>Speaks the text via the loaded screen reader (if any).
|
||||
@@ -108,10 +126,10 @@ namespace stardew_access.ScreenReader
|
||||
/// <param name="interrupt">Whether to skip the currently speaking text or not.</param>
|
||||
public void SayWithTileQuery(String text, int x, int y, Boolean interrupt)
|
||||
{
|
||||
if (MainClass.GetScreenReader() == null)
|
||||
if (MainClass.ScreenReader == null)
|
||||
return;
|
||||
|
||||
MainClass.GetScreenReader().SayWithTileQuery(text, x, y, interrupt);
|
||||
MainClass.ScreenReader.SayWithTileQuery(text, x, y, interrupt);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,49 +11,66 @@ namespace stardew_access
|
||||
{
|
||||
internal static void Initialize()
|
||||
{
|
||||
IModHelper helper = MainClass.ModHelper;
|
||||
//TODO organise this, create separate method for all commands
|
||||
IModHelper? helper = MainClass.ModHelper;
|
||||
if (helper == null)
|
||||
return;
|
||||
|
||||
#region Read Tile
|
||||
helper.ConsoleCommands.Add("readtile", "Toggle read tile feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.readTile = !MainClass.readTile;
|
||||
{
|
||||
MainClass.Config.ReadTile = !MainClass.Config.ReadTile;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.GetMonitor().Log("Read Tile is " + (MainClass.readTile ? "on" : "off"), LogLevel.Info);
|
||||
MainClass.InfoLog("Read Tile is " + (MainClass.Config.ReadTile ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("flooring", "Toggle flooring in read tile.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config.ReadFlooring = !MainClass.Config.ReadFlooring;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.InfoLog("Flooring is " + (MainClass.Config.ReadFlooring ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("snapmouse", "Toggle snap mouse feature.", (string commmand, string[] args) =>
|
||||
helper.ConsoleCommands.Add("watered", "Toggle speaking watered or unwatered for crops.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.snapMouse = !MainClass.snapMouse;
|
||||
MainClass.Config.WateredToggle = !MainClass.Config.WateredToggle;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.GetMonitor().Log("Snap Mouse is " + (MainClass.snapMouse ? "on" : "off"), LogLevel.Info);
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("radar", "Toggle radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.radar = !MainClass.radar;
|
||||
|
||||
MainClass.GetMonitor().Log("Radar " + (MainClass.radar ? "on" : "off"), LogLevel.Info);
|
||||
MainClass.InfoLog("Watered toggle is " + (MainClass.Config.WateredToggle ? "on" : "off"));
|
||||
});
|
||||
#endregion
|
||||
|
||||
#region Radar Feature
|
||||
helper.ConsoleCommands.Add("radar", "Toggle radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config.Radar = !MainClass.Config.Radar;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.InfoLog("Radar " + (MainClass.Config.Radar ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("rdebug", "Toggle debugging in radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.radarDebug = !MainClass.radarDebug;
|
||||
|
||||
MainClass.GetMonitor().Log("Radar debugging " + (MainClass.radarDebug ? "on" : "off"), LogLevel.Info);
|
||||
MainClass.InfoLog("Radar debugging " + (MainClass.radarDebug ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("rstereo", "Toggle stereo sound in radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.radarStereoSound = !MainClass.radarStereoSound;
|
||||
MainClass.Config.RadarStereoSound = !MainClass.Config.RadarStereoSound;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.GetMonitor().Log("Stereo sound is " + (MainClass.radarStereoSound ? "on" : "off"), LogLevel.Info);
|
||||
MainClass.InfoLog("Stereo sound is " + (MainClass.Config.RadarStereoSound ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("rfocus", "Toggle focus mode in radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
bool focus = MainClass.RadarFeature.ToggleFocus();
|
||||
|
||||
MainClass.GetMonitor().Log("Focus mode is " + (focus ? "on" : "off"), LogLevel.Info);
|
||||
MainClass.InfoLog("Focus mode is " + (focus ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("rdelay", "Set the delay of radar feature in milliseconds.", (string commmand, string[] args) =>
|
||||
@@ -72,19 +89,19 @@ namespace stardew_access
|
||||
{
|
||||
MainClass.RadarFeature.delay = delay;
|
||||
if (delay >= 1000)
|
||||
MainClass.GetMonitor().Log($"Delay set to {MainClass.RadarFeature.delay} milliseconds.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Delay set to {MainClass.RadarFeature.delay} milliseconds.");
|
||||
else
|
||||
MainClass.GetMonitor().Log($"Delay should be atleast 1 second or 1000 millisecond long.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Delay should be atleast 1 second or 1000 millisecond long.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Invalid delay amount, it can only be in numeric form.", LogLevel.Info);
|
||||
MainClass.InfoLog("Invalid delay amount, it can only be in numeric form.");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Enter the delay amount (in milliseconds)!", LogLevel.Info);
|
||||
MainClass.InfoLog("Enter the delay amount (in milliseconds)!");
|
||||
}
|
||||
|
||||
});
|
||||
@@ -105,19 +122,19 @@ namespace stardew_access
|
||||
{
|
||||
MainClass.RadarFeature.range = range;
|
||||
if (range >= 2 && range <= 10)
|
||||
MainClass.GetMonitor().Log($"Range set to {MainClass.RadarFeature.range}.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Range set to {MainClass.RadarFeature.range}.");
|
||||
else
|
||||
MainClass.GetMonitor().Log($"Range should be atleast 2 and maximum 10.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Range should be atleast 2 and maximum 10.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Invalid range amount, it can only be in numeric form.", LogLevel.Info);
|
||||
MainClass.InfoLog("Invalid range amount, it can only be in numeric form.");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Enter the range amount!", LogLevel.Info);
|
||||
MainClass.InfoLog("Enter the range amount!");
|
||||
}
|
||||
|
||||
});
|
||||
@@ -136,16 +153,16 @@ namespace stardew_access
|
||||
if (!MainClass.RadarFeature.exclusions.Contains(keyToAdd))
|
||||
{
|
||||
MainClass.RadarFeature.exclusions.Add(keyToAdd);
|
||||
MainClass.GetMonitor().Log($"Added {keyToAdd} key to exclusions list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Added {keyToAdd} key to exclusions list.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log($"{keyToAdd} key already present in the list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"{keyToAdd} key already present in the list.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Unable to add the key to exclusions list.", LogLevel.Info);
|
||||
MainClass.InfoLog("Unable to add the key to exclusions list.");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -161,16 +178,16 @@ namespace stardew_access
|
||||
if (MainClass.RadarFeature.exclusions.Contains(keyToAdd))
|
||||
{
|
||||
MainClass.RadarFeature.exclusions.Remove(keyToAdd);
|
||||
MainClass.GetMonitor().Log($"Removed {keyToAdd} key from exclusions list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Removed {keyToAdd} key from exclusions list.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Cannot find {keyToAdd} key in exclusions list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Cannot find {keyToAdd} key in exclusions list.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Unable to remove the key from exclusions list.", LogLevel.Info);
|
||||
MainClass.InfoLog("Unable to remove the key from exclusions list.");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -183,23 +200,23 @@ namespace stardew_access
|
||||
{
|
||||
toPrint = $"{toPrint}\t{i + 1}: {MainClass.RadarFeature.exclusions[i]}";
|
||||
}
|
||||
MainClass.GetMonitor().Log(toPrint, LogLevel.Info);
|
||||
MainClass.InfoLog(toPrint);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("No exclusions found.", LogLevel.Info);
|
||||
MainClass.InfoLog("No exclusions found.");
|
||||
}
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("reclear", "Clear the focus exclusions in the radar featrure.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.RadarFeature.exclusions.Clear();
|
||||
MainClass.GetMonitor().Log($"Cleared the focus list in the exclusions feature.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Cleared the focus list in the exclusions feature.");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("recount", "Number of exclusions in the radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.GetMonitor().Log($"There are {MainClass.RadarFeature.exclusions.Count} exclusiond in the radar feature.", LogLevel.Info);
|
||||
MainClass.InfoLog($"There are {MainClass.RadarFeature.exclusions.Count} exclusiond in the radar feature.");
|
||||
});
|
||||
#endregion
|
||||
|
||||
@@ -216,16 +233,16 @@ namespace stardew_access
|
||||
if (!MainClass.RadarFeature.focus.Contains(keyToAdd))
|
||||
{
|
||||
MainClass.RadarFeature.focus.Add(keyToAdd);
|
||||
MainClass.GetMonitor().Log($"Added {keyToAdd} key to focus list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Added {keyToAdd} key to focus list.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log($"{keyToAdd} key already present in the list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"{keyToAdd} key already present in the list.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Unable to add the key to focus list.", LogLevel.Info);
|
||||
MainClass.InfoLog("Unable to add the key to focus list.");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -241,16 +258,16 @@ namespace stardew_access
|
||||
if (MainClass.RadarFeature.focus.Contains(keyToAdd))
|
||||
{
|
||||
MainClass.RadarFeature.focus.Remove(keyToAdd);
|
||||
MainClass.GetMonitor().Log($"Removed {keyToAdd} key from focus list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Removed {keyToAdd} key from focus list.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Cannot find {keyToAdd} key in focus list.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Cannot find {keyToAdd} key in focus list.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("Unable to remove the key from focus list.", LogLevel.Info);
|
||||
MainClass.InfoLog("Unable to remove the key from focus list.");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -263,23 +280,23 @@ namespace stardew_access
|
||||
{
|
||||
toPrint = $"{toPrint}\t{i + 1}): {MainClass.RadarFeature.focus[i]}";
|
||||
}
|
||||
MainClass.GetMonitor().Log(toPrint, LogLevel.Info);
|
||||
MainClass.InfoLog(toPrint);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log("No objects found in the focus list.", LogLevel.Info);
|
||||
MainClass.InfoLog("No objects found in the focus list.");
|
||||
}
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("rfclear", "Clear the focus list in the radar featrure.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.RadarFeature.focus.Clear();
|
||||
MainClass.GetMonitor().Log($"Cleared the focus list in the radar feature.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Cleared the focus list in the radar feature.");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("rfcount", "Number of list in the radar feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.GetMonitor().Log($"There are {MainClass.RadarFeature.focus.Count} objects in the focus list in the radar feature.", LogLevel.Info);
|
||||
MainClass.InfoLog($"There are {MainClass.RadarFeature.focus.Count} objects in the focus list in the radar feature.");
|
||||
});
|
||||
#endregion
|
||||
|
||||
@@ -290,14 +307,14 @@ namespace stardew_access
|
||||
{
|
||||
if (Game1.currentLocation is not Farm)
|
||||
{
|
||||
MainClass.GetMonitor().Log("Can only use this command in the farm", LogLevel.Info);
|
||||
MainClass.InfoLog("Can only use this command in the farm");
|
||||
return;
|
||||
}
|
||||
|
||||
string? indexInString = args.ElementAtOrDefault(0);
|
||||
if (indexInString == null)
|
||||
{
|
||||
MainClass.GetMonitor().Log("Enter the index too!", LogLevel.Info);
|
||||
MainClass.InfoLog("Enter the index too!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -306,12 +323,12 @@ namespace stardew_access
|
||||
|
||||
if (!isParsable || !(index >= 0 && index <= 9))
|
||||
{
|
||||
MainClass.GetMonitor().Log("Index can only be a number and from 0 to 9 only", LogLevel.Info);
|
||||
MainClass.InfoLog("Index can only be a number and from 0 to 9 only");
|
||||
return;
|
||||
}
|
||||
|
||||
BuildingNAnimalMenuPatches.marked[index] = new Vector2((int)Game1.player.getTileX(), (int)Game1.player.getTileY());
|
||||
MainClass.GetMonitor().Log($"Location {(int)Game1.player.getTileX()}x {(int)Game1.player.getTileY()}y added at {index} index.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Location {(int)Game1.player.getTileX()}x {(int)Game1.player.getTileY()}y added at {index} index.");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("marklist", "List all marked positions.", (string commmand, string[] args) =>
|
||||
@@ -326,56 +343,28 @@ namespace stardew_access
|
||||
}
|
||||
|
||||
if (toPrint == "")
|
||||
MainClass.GetMonitor().Log("No positions marked!", LogLevel.Info);
|
||||
MainClass.InfoLog("No positions marked!");
|
||||
else
|
||||
MainClass.GetMonitor().Log($"Marked positions:{toPrint}\nOpen command menu and use pageup and pagedown to check the list", LogLevel.Info);
|
||||
MainClass.InfoLog($"Marked positions:{toPrint}\nOpen command menu and use pageup and pagedown to check the list");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("buildlist", "List all buildings for selection for upgrading/demolishing/painting", (string commmand, string[] args) =>
|
||||
{
|
||||
if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu) || !BuildingNAnimalMenuPatches.isOnFarm)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Cannot list buildings.", LogLevel.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
string toPrint = "";
|
||||
Farm farm = (Farm)Game1.getLocationFromName("Farm");
|
||||
Netcode.NetCollection<Building> buildings = farm.buildings;
|
||||
int buildingIndex = 0;
|
||||
|
||||
for (int i = 0; i < buildings.Count; i++)
|
||||
{
|
||||
string? name = buildings[i].nameOfIndoorsWithoutUnique;
|
||||
name = (name == "null") ? buildings[i].buildingType.Value : name;
|
||||
|
||||
BuildingNAnimalMenuPatches.availableBuildings[buildingIndex] = buildings[i];
|
||||
toPrint = $"{toPrint}\nIndex {buildingIndex}: {name}: At {buildings[i].tileX}x and {buildings[i].tileY}y";
|
||||
++buildingIndex;
|
||||
}
|
||||
|
||||
if (toPrint == "")
|
||||
{
|
||||
MainClass.GetMonitor().Log("No appropriate buildings to list", LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Available buildings:{toPrint}\nOpen command menu and use pageup and pagedown to check the list", LogLevel.Info);
|
||||
}
|
||||
onBuildListCalled();
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("buildsel", "Select the building index which you want to upgrade/demolish/paint", (string commmand, string[] args) =>
|
||||
{
|
||||
if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu) || !BuildingNAnimalMenuPatches.isOnFarm)
|
||||
if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu && Game1.activeClickableMenu is not AnimalQueryMenu) || !BuildingNAnimalMenuPatches.isOnFarm)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Cannot select building.", LogLevel.Info);
|
||||
MainClass.InfoLog($"Cannot select building.");
|
||||
return;
|
||||
}
|
||||
|
||||
string? indexInString = args.ElementAtOrDefault(0);
|
||||
if (indexInString == null)
|
||||
{
|
||||
MainClass.GetMonitor().Log("Enter the index of the building too! Use buildlist", LogLevel.Info);
|
||||
MainClass.InfoLog("Enter the index of the building too! Use buildlist");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -384,7 +373,7 @@ namespace stardew_access
|
||||
|
||||
if (!isParsable)
|
||||
{
|
||||
MainClass.GetMonitor().Log("Index can only be a number.", LogLevel.Info);
|
||||
MainClass.InfoLog("Index can only be a number.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -398,13 +387,13 @@ namespace stardew_access
|
||||
{
|
||||
if (BuildingNAnimalMenuPatches.availableBuildings[index] == null)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"No building found with index {index}. Use buildlist.", LogLevel.Info);
|
||||
MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (positionIndexInString == null)
|
||||
{
|
||||
MainClass.GetMonitor().Log("Enter the index of marked place too! Use marklist.", LogLevel.Info);
|
||||
MainClass.InfoLog("Enter the index of marked place too! Use marklist.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -412,7 +401,7 @@ namespace stardew_access
|
||||
|
||||
if (!isParsable)
|
||||
{
|
||||
MainClass.GetMonitor().Log("Index can only be a number.", LogLevel.Info);
|
||||
MainClass.InfoLog("Index can only be a number.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -421,7 +410,7 @@ namespace stardew_access
|
||||
{
|
||||
if (BuildingNAnimalMenuPatches.marked[index] == Vector2.Zero)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"No marked position found at {index} index.", LogLevel.Info);
|
||||
MainClass.InfoLog($"No marked position found at {index} index.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -429,14 +418,21 @@ namespace stardew_access
|
||||
{
|
||||
if (BuildingNAnimalMenuPatches.availableBuildings[index] == null)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"No building found with index {index}. Use buildlist.", LogLevel.Info);
|
||||
MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string? response = null;
|
||||
|
||||
if (Game1.activeClickableMenu is PurchaseAnimalsMenu) { BuildingNAnimalMenuPatches.PurchaseAnimal(BuildingNAnimalMenuPatches.availableBuildings[index]); }
|
||||
if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
||||
{
|
||||
BuildingNAnimalMenuPatches.PurchaseAnimal(BuildingNAnimalMenuPatches.availableBuildings[index]);
|
||||
}
|
||||
else if (Game1.activeClickableMenu is AnimalQueryMenu)
|
||||
{
|
||||
BuildingNAnimalMenuPatches.MoveAnimal(BuildingNAnimalMenuPatches.availableBuildings[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BuildingNAnimalMenuPatches.isConstructing && !BuildingNAnimalMenuPatches.isUpgrading) { response = BuildingNAnimalMenuPatches.Contstruct(BuildingNAnimalMenuPatches.marked[index]); }
|
||||
@@ -448,17 +444,92 @@ namespace stardew_access
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
MainClass.GetMonitor().Log(response, LogLevel.Info);
|
||||
MainClass.InfoLog(response);
|
||||
}
|
||||
});
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
helper.ConsoleCommands.Add("refsr", "Refresh screen reader", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.GetScreenReader().InitializeScreenReader();
|
||||
{
|
||||
MainClass.ScreenReader.InitializeScreenReader();
|
||||
|
||||
MainClass.GetMonitor().Log("Screen Reader refreshed!", LogLevel.Info);
|
||||
MainClass.InfoLog("Screen Reader refreshed!");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("refmc", "Refresh mod config", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config = helper.ReadConfig<ModConfig>();
|
||||
|
||||
MainClass.InfoLog("Mod Config refreshed!");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("refst", "Refresh static tiles", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.STiles = new Features.StaticTiles();
|
||||
|
||||
MainClass.InfoLog("Static tiles refreshed!");
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("hnspercent", "Toggle between speaking in percentage or full health and stamina.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config.HealthNStaminaInPercentage = !MainClass.Config.HealthNStaminaInPercentage;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.InfoLog("Speaking in percentage is " + (MainClass.Config.HealthNStaminaInPercentage ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("snapmouse", "Toggle snap mouse feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config.SnapMouse = !MainClass.Config.SnapMouse;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.InfoLog("Snap Mouse is " + (MainClass.Config.SnapMouse ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("warning", "Toggle warnings feature.", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config.Warning = !MainClass.Config.Warning;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.InfoLog("Warnings is " + (MainClass.Config.Warning ? "on" : "off"));
|
||||
});
|
||||
|
||||
helper.ConsoleCommands.Add("tts", "Toggles the screen reader/tts", (string commmand, string[] args) =>
|
||||
{
|
||||
MainClass.Config.TTS = !MainClass.Config.TTS;
|
||||
helper.WriteConfig(MainClass.Config);
|
||||
|
||||
MainClass.InfoLog("TTS is " + (MainClass.Config.TTS ? "on" : "off"));
|
||||
});
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal static void onBuildListCalled()
|
||||
{
|
||||
string toPrint = "";
|
||||
Farm farm = (Farm)Game1.getLocationFromName("Farm");
|
||||
Netcode.NetCollection<Building> buildings = farm.buildings;
|
||||
int buildingIndex = 0;
|
||||
|
||||
for (int i = 0; i < buildings.Count; i++)
|
||||
{
|
||||
string? name = buildings[i].nameOfIndoorsWithoutUnique;
|
||||
name = (name == "null") ? buildings[i].buildingType.Value : name;
|
||||
|
||||
BuildingNAnimalMenuPatches.availableBuildings[buildingIndex] = buildings[i];
|
||||
toPrint = $"{toPrint}\nIndex {buildingIndex}: {name}: At {buildings[i].tileX}x and {buildings[i].tileY}y";
|
||||
++buildingIndex;
|
||||
}
|
||||
|
||||
if (toPrint == "")
|
||||
{
|
||||
MainClass.InfoLog("No appropriate buildings to list");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.InfoLog($"Available buildings:{toPrint}\nOpen command menu and use pageup and pagedown to check the list");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework.Audio;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
|
||||
namespace stardew_access
|
||||
@@ -16,6 +15,9 @@ namespace stardew_access
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
Dictionary<String, TYPE> soundEffects = new Dictionary<String, TYPE>();
|
||||
|
||||
soundEffects.Add("drop_item", TYPE.Sound);
|
||||
@@ -55,7 +57,7 @@ namespace stardew_access
|
||||
}
|
||||
|
||||
SoundEffect effect;
|
||||
string filePath = Path.Combine(MainClass.ModHelper.DirectoryPath, "sounds", $"{soundEffect.Key}.wav");
|
||||
string filePath = Path.Combine(MainClass.ModHelper.DirectoryPath, "assets", "sounds", $"{soundEffect.Key}.wav");
|
||||
using (FileStream stream = new(filePath, FileMode.Open))
|
||||
{
|
||||
effect = SoundEffect.FromStream(stream);
|
||||
@@ -71,7 +73,7 @@ namespace stardew_access
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to initialize custom sounds:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to initialize custom sounds:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,115 +6,185 @@ namespace stardew_access.Features
|
||||
internal class CurrentPlayer
|
||||
{
|
||||
|
||||
public static int getHealth()
|
||||
/// <summary>
|
||||
/// Returns the percentage health remaining of player.
|
||||
/// </summary>
|
||||
public static int PercentHealth
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
int maxHealth = Game1.player.maxHealth;
|
||||
int currentHealth = Game1.player.health;
|
||||
|
||||
int healthPercentage = (int)(currentHealth * 100) / maxHealth;
|
||||
return healthPercentage;
|
||||
}
|
||||
|
||||
public static int getStamina()
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
int maxStamina = Game1.player.maxStamina;
|
||||
int currentStamine = (int)Game1.player.stamina;
|
||||
|
||||
int staminaPercentage = (int)(currentStamine * 100) / maxStamina;
|
||||
|
||||
return staminaPercentage;
|
||||
}
|
||||
|
||||
public static int getPositionX()
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
int x = (int)Game1.player.getTileLocation().X;
|
||||
return x;
|
||||
}
|
||||
|
||||
public static int getPositionY()
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
int y = (int)Game1.player.getTileLocation().Y;
|
||||
return y;
|
||||
}
|
||||
|
||||
public static string getTimeOfDay()
|
||||
{
|
||||
int timeOfDay = Game1.timeOfDay;
|
||||
|
||||
int minutes = timeOfDay % 100;
|
||||
int hours = timeOfDay / 100;
|
||||
string amOrpm = "A M";
|
||||
if (hours >= 12)
|
||||
get
|
||||
{
|
||||
amOrpm = "P M";
|
||||
if (hours > 12)
|
||||
hours -= 12;
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
return (CurrentHealth * 100) / Game1.player.maxHealth; ;
|
||||
}
|
||||
|
||||
return $"{hours}:{minutes} {amOrpm}";
|
||||
}
|
||||
|
||||
public static string getSeason()
|
||||
/// <summary>
|
||||
/// Returns the total health player has currently
|
||||
/// </summary>
|
||||
public static int CurrentHealth
|
||||
{
|
||||
return Game1.CurrentSeasonDisplayName;
|
||||
}
|
||||
|
||||
public static int getDate()
|
||||
{
|
||||
return Game1.dayOfMonth;
|
||||
}
|
||||
|
||||
public static string getDay()
|
||||
{
|
||||
return Game1.Date.DayOfWeek.ToString();
|
||||
}
|
||||
|
||||
public static int getMoney()
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return -1;
|
||||
|
||||
return Game1.player.Money;
|
||||
}
|
||||
|
||||
public static Vector2 getNextTile()
|
||||
{
|
||||
int x = Game1.player.GetBoundingBox().Center.X;
|
||||
int y = Game1.player.GetBoundingBox().Center.Y;
|
||||
|
||||
int offset = 64;
|
||||
|
||||
switch (Game1.player.FacingDirection)
|
||||
get
|
||||
{
|
||||
case 0:
|
||||
y -= offset;
|
||||
break;
|
||||
case 1:
|
||||
x += offset;
|
||||
break;
|
||||
case 2:
|
||||
y += offset;
|
||||
break;
|
||||
case 3:
|
||||
x -= offset;
|
||||
break;
|
||||
}
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
x /= Game1.tileSize;
|
||||
y /= Game1.tileSize;
|
||||
return new Vector2(x, y);
|
||||
return Game1.player.health;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the percentage stamine/energy remaining of player.
|
||||
/// </summary>
|
||||
public static int PercentStamina
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
return (CurrentStamina * 100) / Game1.player.maxStamina.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total stamina player has currently
|
||||
/// </summary>
|
||||
public static int CurrentStamina
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
return (int)Game1.player.stamina;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the tile location of the player
|
||||
/// </summary>
|
||||
public static Vector2 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return Vector2.Zero;
|
||||
|
||||
return Game1.player.getTileLocation();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the X coordinate of the player
|
||||
/// </summary>
|
||||
public static int PositionX
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
return (int)Position.X;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Y coordinate of the player
|
||||
/// </summary>
|
||||
public static int PositionY
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return 0;
|
||||
|
||||
return (int)Position.Y;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the time in the 12 hours format
|
||||
/// </summary>
|
||||
public static string TimeOfDay
|
||||
{
|
||||
get
|
||||
{
|
||||
int timeOfDay = Game1.timeOfDay;
|
||||
|
||||
int minutes = timeOfDay % 100;
|
||||
int hours = timeOfDay / 100;
|
||||
string amOrpm = hours / 12 == 1 ? "PM" : "AM";
|
||||
hours = hours % 12;
|
||||
if (hours == 0) hours = 12;
|
||||
return $"{hours}:{minutes:00} {amOrpm}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current season
|
||||
/// </summary>
|
||||
public static string Season => Game1.CurrentSeasonDisplayName;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current date of month
|
||||
/// </summary>
|
||||
public static int Date => Game1.dayOfMonth;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current day of week
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string Day => Game1.Date.DayOfWeek.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of money the player has currently
|
||||
/// </summary>
|
||||
public static int Money
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Game1.player == null)
|
||||
return -1;
|
||||
|
||||
return Game1.player.Money;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the tile position of the tile the player is facing
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public static Vector2 FacingTile
|
||||
{
|
||||
get
|
||||
{
|
||||
int x = Game1.player.GetBoundingBox().Center.X;
|
||||
int y = Game1.player.GetBoundingBox().Center.Y;
|
||||
|
||||
int offset = 64;
|
||||
|
||||
switch (Game1.player.FacingDirection)
|
||||
{
|
||||
case 0:
|
||||
y -= offset;
|
||||
break;
|
||||
case 1:
|
||||
x += offset;
|
||||
break;
|
||||
case 2:
|
||||
y += offset;
|
||||
break;
|
||||
case 3:
|
||||
x -= offset;
|
||||
break;
|
||||
}
|
||||
|
||||
x /= Game1.tileSize;
|
||||
y /= Game1.tileSize;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ namespace stardew_access.Features
|
||||
return;
|
||||
|
||||
previousSlotItem = currentSlotItem;
|
||||
MainClass.GetScreenReader().Say($"{currentSlotItem.DisplayName} Selected", true);
|
||||
MainClass.ScreenReader.Say($"{currentSlotItem.DisplayName} Selected", true);
|
||||
}
|
||||
|
||||
// Narrates current location's name
|
||||
@@ -38,38 +38,11 @@ namespace stardew_access.Features
|
||||
return;
|
||||
|
||||
previousLocation = currentLocation;
|
||||
MainClass.GetScreenReader().Say($"{currentLocation.Name} Entered", true);
|
||||
MainClass.ScreenReader.Say($"{currentLocation.Name} Entered", true);
|
||||
}
|
||||
|
||||
public static void SnapMouseToPlayer()
|
||||
public static void narrateHudMessages()
|
||||
{
|
||||
int x = Game1.player.GetBoundingBox().Center.X - Game1.viewport.X;
|
||||
int y = Game1.player.GetBoundingBox().Center.Y - Game1.viewport.Y;
|
||||
|
||||
int offset = 64;
|
||||
|
||||
switch (Game1.player.FacingDirection)
|
||||
{
|
||||
case 0:
|
||||
y -= offset;
|
||||
break;
|
||||
case 1:
|
||||
x += offset;
|
||||
break;
|
||||
case 2:
|
||||
y += offset;
|
||||
break;
|
||||
case 3:
|
||||
x -= offset;
|
||||
break;
|
||||
}
|
||||
|
||||
Game1.setMousePosition(x, y);
|
||||
}
|
||||
|
||||
public static async void narrateHudMessages()
|
||||
{
|
||||
MainClass.isNarratingHudMessage = true;
|
||||
try
|
||||
{
|
||||
if (Game1.hudMessages.Count > 0)
|
||||
@@ -89,18 +62,16 @@ namespace stardew_access.Features
|
||||
{
|
||||
MainClass.hudMessageQueryKey = searchQuery;
|
||||
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate hud messages:\n{e.Message}\n{e.StackTrace}", StardewModdingAPI.LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate hud messages:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
|
||||
await Task.Delay(300);
|
||||
MainClass.isNarratingHudMessage = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,48 +1,9 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewValley;
|
||||
using StardewValley.Objects;
|
||||
using StardewValley.TerrainFeatures;
|
||||
|
||||
namespace stardew_access.Features
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This is a custom enum class and contains the name of groups the objects are divided into for the feature
|
||||
/// </summary>
|
||||
public class CATEGORY
|
||||
{
|
||||
private string _typeKeyWord;
|
||||
|
||||
private CATEGORY(string typeKeyWord)
|
||||
{
|
||||
_typeKeyWord = typeKeyWord;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _typeKeyWord;
|
||||
}
|
||||
|
||||
public static CATEGORY Farmers = new CATEGORY("farmer");
|
||||
public static CATEGORY FarmAnimals = new CATEGORY("animal");
|
||||
public static CATEGORY NPCs = new CATEGORY("npc");
|
||||
public static CATEGORY Furnitures = new CATEGORY("furniture");
|
||||
public static CATEGORY Flooring = new CATEGORY("flooring");
|
||||
public static CATEGORY Debris = new CATEGORY("debris");
|
||||
public static CATEGORY Crops = new CATEGORY("crop");
|
||||
public static CATEGORY Trees = new CATEGORY("tree");
|
||||
public static CATEGORY Bush = new CATEGORY("bush");
|
||||
public static CATEGORY Buildings = new CATEGORY("building");
|
||||
public static CATEGORY MineItems = new CATEGORY("mine item");
|
||||
public static CATEGORY ResourceClumps = new CATEGORY("resource clump");
|
||||
public static CATEGORY Chests = new CATEGORY("chest");
|
||||
public static CATEGORY JunimoBundle = new CATEGORY("bundle");
|
||||
public static CATEGORY Doors = new CATEGORY("door"); // Also includes ladders and elevators
|
||||
public static CATEGORY Others = new CATEGORY("other");
|
||||
public static CATEGORY WaterTiles = new CATEGORY("water");
|
||||
|
||||
}
|
||||
|
||||
public class Radar
|
||||
{
|
||||
private List<Vector2> closed;
|
||||
@@ -80,7 +41,11 @@ namespace stardew_access.Features
|
||||
exclusions.Add("tree");
|
||||
exclusions.Add("flooring");
|
||||
exclusions.Add("water");
|
||||
exclusions.Add("debris");
|
||||
exclusions.Add("grass");
|
||||
exclusions.Add("decoration");
|
||||
exclusions.Add("bridge");
|
||||
exclusions.Add("other");
|
||||
|
||||
/* Not excluded Categories
|
||||
*
|
||||
@@ -89,19 +54,22 @@ namespace stardew_access.Features
|
||||
* exclusions.Add("animal");
|
||||
* exclusions.Add("npc");
|
||||
* exclusions.Add("furniture")
|
||||
* exclusions.Add("other");
|
||||
* exclusions.Add("building");
|
||||
* exclusions.Add("resource clump");
|
||||
* exclusions.Add("mine item");
|
||||
* exclusions.Add("chest");
|
||||
* exclusions.Add("container");
|
||||
* exclusions.Add("bundle");
|
||||
* exclusions.Add("door");
|
||||
* exclusions.Add("machine");
|
||||
* exclusions.Add("interactable");
|
||||
*/
|
||||
}
|
||||
|
||||
public async void Run()
|
||||
public void Run()
|
||||
{
|
||||
if (MainClass.radarDebug)
|
||||
MainClass.GetMonitor().Log($"\n\nRead Tile started", StardewModdingAPI.LogLevel.Debug);
|
||||
MainClass.DebugLog($"\n\nRead Tile started");
|
||||
|
||||
isRunning = true;
|
||||
Vector2 currPosition = Game1.player.getTileLocation();
|
||||
|
||||
closed.Clear();
|
||||
@@ -111,10 +79,7 @@ namespace stardew_access.Features
|
||||
SearchNearbyTiles(currPosition, range);
|
||||
|
||||
if (MainClass.radarDebug)
|
||||
MainClass.GetMonitor().Log($"\nRead Tile stopped\n\n", StardewModdingAPI.LogLevel.Debug);
|
||||
|
||||
await Task.Delay(delay);
|
||||
isRunning = false;
|
||||
MainClass.DebugLog($"\nRead Tile stopped\n\n");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,7 +97,6 @@ namespace stardew_access.Features
|
||||
List<Vector2> searched = new List<Vector2>();
|
||||
int[] dirX = { -1, 0, 1, 0 };
|
||||
int[] dirY = { 0, 1, 0, -1 };
|
||||
int count = 0;
|
||||
|
||||
toSearch.Enqueue(center);
|
||||
searched.Add(center);
|
||||
@@ -151,7 +115,6 @@ namespace stardew_access.Features
|
||||
detectedTiles.Add(item, (tileInfo.Item2, tileInfo.Item3));
|
||||
}
|
||||
}
|
||||
count++;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -168,6 +131,52 @@ namespace stardew_access.Features
|
||||
return detectedTiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search the entire location using Breadth First Search algorithm(BFS).
|
||||
/// </summary>
|
||||
/// <returns>A dictionary with all the detected tiles along with the name of the object on it and it's category.</returns>
|
||||
public Dictionary<Vector2, (string, string)> SearchLocation()
|
||||
{
|
||||
Dictionary<Vector2, (string, string)> detectedTiles = new Dictionary<Vector2, (string, string)>();
|
||||
Vector2 position = Vector2.Zero;
|
||||
(bool, string? name, string category) tileInfo;
|
||||
|
||||
Queue<Vector2> toSearch = new Queue<Vector2>();
|
||||
List<Vector2> searched = new List<Vector2>();
|
||||
int[] dirX = { -1, 0, 1, 0 };
|
||||
int[] dirY = { 0, 1, 0, -1 };
|
||||
int count = 0;
|
||||
|
||||
toSearch.Enqueue(Game1.player.getTileLocation());
|
||||
searched.Add(Game1.player.getTileLocation());
|
||||
|
||||
while (toSearch.Count > 0)
|
||||
{
|
||||
Vector2 item = toSearch.Dequeue();
|
||||
tileInfo = CheckTile(item, true);
|
||||
if (tileInfo.Item1 && tileInfo.name != null)
|
||||
{
|
||||
// Add detected tile to the dictionary
|
||||
detectedTiles.Add(item, (tileInfo.name, tileInfo.category));
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vector2 dir = new Vector2(item.X + dirX[i], item.Y + dirY[i]);
|
||||
|
||||
if (!searched.Contains(dir) && (TileInfo.isWarpPointAtTile((int)dir.X, (int)dir.Y) || Game1.currentLocation.isTileOnMap(dir)))
|
||||
{
|
||||
toSearch.Enqueue(dir);
|
||||
searched.Add(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return detectedTiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the provided tile position is within the range/radius and whether the tile has already been checked or not.
|
||||
/// </summary>
|
||||
@@ -189,16 +198,16 @@ namespace stardew_access.Features
|
||||
return true;
|
||||
}
|
||||
|
||||
public (bool, string?, string) CheckTile(Vector2 position)
|
||||
public (bool, string? name, string category) CheckTile(Vector2 position, bool lessInfo = false)
|
||||
{
|
||||
(string?, CATEGORY?) tileDetail = ReadTile.getNameWithCategoryAtTile(position);
|
||||
if (tileDetail.Item1 == null)
|
||||
(string? name, CATEGORY? category) tileDetail = TileInfo.getNameWithCategoryAtTile(position, lessInfo);
|
||||
if (tileDetail.name == null)
|
||||
return (false, null, CATEGORY.Others.ToString());
|
||||
|
||||
if (tileDetail.Item2 == null)
|
||||
tileDetail.Item2 = CATEGORY.Others;
|
||||
if (tileDetail.category == null)
|
||||
tileDetail.category = CATEGORY.Others;
|
||||
|
||||
return (true, tileDetail.Item1, tileDetail.Item2.ToString());
|
||||
return (true, tileDetail.name, tileDetail.category.ToString());
|
||||
|
||||
}
|
||||
|
||||
@@ -208,9 +217,9 @@ namespace stardew_access.Features
|
||||
{
|
||||
if (Game1.currentLocation.isObjectAtTile((int)position.X, (int)position.Y))
|
||||
{
|
||||
(string?, CATEGORY) objDetails = ReadTile.getObjectAtTile((int)position.X, (int)position.Y);
|
||||
string? objectName = objDetails.Item1;
|
||||
CATEGORY category = objDetails.Item2;
|
||||
(string? name, CATEGORY category) objDetails = TileInfo.getObjectAtTile((int)position.X, (int)position.Y);
|
||||
string? objectName = objDetails.name;
|
||||
CATEGORY category = objDetails.category;
|
||||
StardewValley.Object obj = Game1.currentLocation.getObjectAtTile((int)position.X, (int)position.Y);
|
||||
|
||||
if (objectName != null)
|
||||
@@ -232,19 +241,19 @@ namespace stardew_access.Features
|
||||
}
|
||||
else
|
||||
{
|
||||
(string?, CATEGORY?) tileDetail = ReadTile.getNameWithCategoryAtTile(position);
|
||||
if (tileDetail.Item1 != null)
|
||||
(string? name, CATEGORY? category) tileDetail = TileInfo.getNameWithCategoryAtTile(position);
|
||||
if (tileDetail.name != null)
|
||||
{
|
||||
if (tileDetail.Item2 == null)
|
||||
tileDetail.Item2 = CATEGORY.Others;
|
||||
if (tileDetail.category == null)
|
||||
tileDetail.category = CATEGORY.Others;
|
||||
|
||||
PlaySoundAt(position, tileDetail.Item1, tileDetail.Item2);
|
||||
PlaySoundAt(position, tileDetail.name, tileDetail.category);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"{e.Message}\n{e.StackTrace}\n{e.Source}", StardewModdingAPI.LogLevel.Error);
|
||||
MainClass.ErrorLog($"{e.Message}\n{e.StackTrace}\n{e.Source}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +262,7 @@ namespace stardew_access.Features
|
||||
#region Check whether to skip the object or not
|
||||
|
||||
// Skip if player is directly looking at the tile
|
||||
if (CurrentPlayer.getNextTile().Equals(position))
|
||||
if (CurrentPlayer.FacingTile.Equals(position))
|
||||
return;
|
||||
|
||||
if (!radarFocus)
|
||||
@@ -296,7 +305,7 @@ namespace stardew_access.Features
|
||||
#endregion
|
||||
|
||||
if (MainClass.radarDebug)
|
||||
MainClass.GetMonitor().Log($"{radarFocus}\tObject:{searchQuery.ToLower().Trim()}\tPosition: X={position.X} Y={position.Y}", StardewModdingAPI.LogLevel.Debug);
|
||||
MainClass.ErrorLog($"{radarFocus}\tObject:{searchQuery.ToLower().Trim()}\tPosition: X={position.X} Y={position.Y}");
|
||||
|
||||
int px = (int)Game1.player.getTileX(); // Player's X postion
|
||||
int py = (int)Game1.player.getTileY(); // Player's Y postion
|
||||
@@ -330,7 +339,7 @@ namespace stardew_access.Features
|
||||
{
|
||||
string soundName = $"_{post}";
|
||||
|
||||
if (!MainClass.radarStereoSound)
|
||||
if (!MainClass.Config.RadarStereoSound)
|
||||
soundName = $"_mono{soundName}";
|
||||
|
||||
if (category == CATEGORY.Farmers) // Villagers and farmers
|
||||
@@ -353,7 +362,7 @@ namespace stardew_access.Features
|
||||
soundName = $"obj{soundName}";
|
||||
else if (category == CATEGORY.MineItems) // Mine items
|
||||
soundName = $"obj{soundName}";
|
||||
else if (category == CATEGORY.Chests) // Chests
|
||||
else if (category == CATEGORY.Containers) // Chests
|
||||
soundName = $"obj{soundName}";
|
||||
else if (category == CATEGORY.Debris) // Grass and debris
|
||||
soundName = $"obj{soundName}";
|
||||
|
@@ -1,54 +1,105 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley.Buildings;
|
||||
using StardewValley.Locations;
|
||||
using StardewValley.Objects;
|
||||
using StardewValley.TerrainFeatures;
|
||||
|
||||
namespace stardew_access.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the name and information about a tile.
|
||||
/// </summary>
|
||||
public class ReadTile
|
||||
{
|
||||
public static bool isReadingTile = false;
|
||||
public static Vector2 prevTile;
|
||||
private bool isBusy; // To pause execution of run method between fixed intervals
|
||||
private int delay; // Length of each interval (in ms)
|
||||
private bool shouldPause; // To pause the execution
|
||||
private Vector2 prevTile;
|
||||
|
||||
public ReadTile()
|
||||
{
|
||||
isReadingTile = false;
|
||||
isBusy = false;
|
||||
delay = 100;
|
||||
}
|
||||
|
||||
public static async void run(bool manuallyTriggered = false)
|
||||
public void update()
|
||||
{
|
||||
isReadingTile = true;
|
||||
if (this.isBusy)
|
||||
return;
|
||||
|
||||
if (this.shouldPause)
|
||||
return;
|
||||
|
||||
this.isBusy = true;
|
||||
this.run();
|
||||
Task.Delay(delay).ContinueWith(_ => { this.isBusy = false; });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pauses the feature for the provided time.
|
||||
/// </summary>
|
||||
/// <param name="time">The amount of time we want to pause the execution (in ms).<br/>Default is 2500 (2.5s).</param>
|
||||
public void pauseUntil(int time = 2500)
|
||||
{
|
||||
this.shouldPause = true;
|
||||
Task.Delay(time).ContinueWith(_ => { this.shouldPause = false; });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pauses the feature
|
||||
/// </summary>
|
||||
public void pause()
|
||||
{
|
||||
this.shouldPause = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resumes the feature
|
||||
/// </summary>
|
||||
public void resume()
|
||||
{
|
||||
this.shouldPause = false;
|
||||
}
|
||||
|
||||
public void run(bool manuallyTriggered = false, bool playersPosition = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
#region Get Next Grab Tile
|
||||
Vector2 tile = CurrentPlayer.getNextTile();
|
||||
int x = (int)tile.X;
|
||||
int y = (int)tile.Y;
|
||||
Vector2 tile;
|
||||
|
||||
#region Get Tile
|
||||
int x, y;
|
||||
if (!playersPosition)
|
||||
{
|
||||
// Grab tile
|
||||
tile = CurrentPlayer.FacingTile;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player's standing tile
|
||||
tile = CurrentPlayer.Position;
|
||||
}
|
||||
x = (int)tile.X;
|
||||
y = (int)tile.Y;
|
||||
#endregion
|
||||
|
||||
if (Context.IsPlayerFree)
|
||||
{
|
||||
if (!manuallyTriggered && prevTile != tile)
|
||||
{
|
||||
if (MainClass.GetScreenReader() != null)
|
||||
MainClass.GetScreenReader().PrevTextTile = " ";
|
||||
if (MainClass.ScreenReader != null)
|
||||
MainClass.ScreenReader.PrevTextTile = " ";
|
||||
}
|
||||
|
||||
bool isColliding = isCollidingAtTile(x, y);
|
||||
bool isColliding = TileInfo.isCollidingAtTile(x, y);
|
||||
|
||||
string? toSpeak = getNameAtTile(tile);
|
||||
(string? name, string? category) info = TileInfo.getNameWithCategoryNameAtTile(tile);
|
||||
|
||||
#region Narrate toSpeak
|
||||
if (toSpeak != null)
|
||||
if (MainClass.GetScreenReader() != null)
|
||||
if (info.name != null)
|
||||
if (MainClass.ScreenReader != null)
|
||||
if (manuallyTriggered)
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say($"{info.name}, Category: {info.category}", true);
|
||||
else
|
||||
MainClass.GetScreenReader().SayWithTileQuery(toSpeak, x, y, true);
|
||||
MainClass.ScreenReader.SayWithTileQuery(info.name, x, y, true);
|
||||
#endregion
|
||||
|
||||
#region Play colliding sound effect
|
||||
@@ -58,865 +109,15 @@ namespace stardew_access.Features
|
||||
}
|
||||
#endregion
|
||||
|
||||
prevTile = tile;
|
||||
if (!manuallyTriggered)
|
||||
prevTile = tile;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Error in Read Tile:\n{e.Message}\n{e.StackTrace}", LogLevel.Debug);
|
||||
MainClass.ErrorLog($"Error in Read Tile:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
isReadingTile = false;
|
||||
}
|
||||
|
||||
///<summary>Returns the name of the object at tile alongwith it's category's name</summary>
|
||||
public static (string?, string?) getNameWithCategoryNameAtTile(Vector2 tile)
|
||||
{
|
||||
(string?, CATEGORY?) tileDetail = getNameWithCategoryAtTile(tile);
|
||||
|
||||
if (tileDetail.Item2 == null)
|
||||
tileDetail.Item2 = CATEGORY.Others;
|
||||
|
||||
return (tileDetail.Item1, tileDetail.Item2.ToString());
|
||||
}
|
||||
|
||||
///<summary>Returns the name of the object at tile alongwith it's category</summary>
|
||||
public static (string?, CATEGORY?) getNameWithCategoryAtTile(Vector2 tile)
|
||||
{
|
||||
int x = (int)tile.X;
|
||||
int y = (int)tile.Y;
|
||||
string? toReturn = "";
|
||||
CATEGORY? category = CATEGORY.Others;
|
||||
|
||||
bool isColliding = isCollidingAtTile(x, y);
|
||||
Dictionary<Vector2, Netcode.NetRef<TerrainFeature>> terrainFeature = Game1.currentLocation.terrainFeatures.FieldDict;
|
||||
string? door = getDoorAtTile(x, y);
|
||||
(CATEGORY?, string?) tileInfo = getTileInfo(x, y);
|
||||
string? junimoBundle = getJunimoBundleAt(x, y);
|
||||
string? resourceClump = getResourceClumpAtTile(x, y);
|
||||
string? farmAnimal = getFarmAnimalAt(Game1.currentLocation, x, y);
|
||||
|
||||
if (Game1.currentLocation.isCharacterAtTile(tile) != null)
|
||||
{
|
||||
NPC npc = Game1.currentLocation.isCharacterAtTile(tile);
|
||||
toReturn = npc.displayName;
|
||||
if (npc.isVillager() || npc.CanSocialize)
|
||||
category = CATEGORY.Farmers;
|
||||
else
|
||||
category = CATEGORY.NPCs;
|
||||
}
|
||||
else if (farmAnimal != null)
|
||||
{
|
||||
toReturn = farmAnimal;
|
||||
category = CATEGORY.FarmAnimals;
|
||||
}
|
||||
else if (Game1.currentLocation.isWaterTile(x, y) && isColliding)
|
||||
{
|
||||
toReturn = "Water";
|
||||
category = CATEGORY.WaterTiles;
|
||||
}
|
||||
else if (Game1.currentLocation.isObjectAtTile(x, y))
|
||||
{
|
||||
(string?, CATEGORY?) obj = getObjectAtTile(x, y);
|
||||
toReturn = obj.Item1;
|
||||
category = obj.Item2;
|
||||
}
|
||||
else if (terrainFeature.ContainsKey(tile))
|
||||
{
|
||||
(string?, CATEGORY) tf = getTerrainFeatureAtTile(terrainFeature[tile]);
|
||||
string? terrain = tf.Item1;
|
||||
if (terrain != null)
|
||||
{
|
||||
toReturn = terrain;
|
||||
category = tf.Item2;
|
||||
}
|
||||
|
||||
}
|
||||
else if (Game1.currentLocation.getLargeTerrainFeatureAt(x, y) != null)
|
||||
{
|
||||
toReturn = getBushAtTile(x, y);
|
||||
category = CATEGORY.Bush;
|
||||
}
|
||||
else if (resourceClump != null)
|
||||
{
|
||||
toReturn = resourceClump;
|
||||
category = CATEGORY.ResourceClumps;
|
||||
}
|
||||
else if (door != null)
|
||||
{
|
||||
toReturn = door;
|
||||
category = CATEGORY.Doors;
|
||||
}
|
||||
else if (isMineDownLadderAtTile(x, y))
|
||||
{
|
||||
toReturn = "Ladder";
|
||||
category = CATEGORY.Doors;
|
||||
}
|
||||
else if (isMineUpLadderAtTile(x, y))
|
||||
{
|
||||
toReturn = "Up Ladder";
|
||||
category = CATEGORY.Doors;
|
||||
}
|
||||
else if (isElevatorAtTile(x, y))
|
||||
{
|
||||
toReturn = "Elevator";
|
||||
category = CATEGORY.Doors;
|
||||
}
|
||||
else if (tileInfo.Item2 != null)
|
||||
{
|
||||
toReturn = tileInfo.Item2;
|
||||
category = tileInfo.Item1;
|
||||
}
|
||||
else if (junimoBundle != null)
|
||||
{
|
||||
toReturn = junimoBundle;
|
||||
category = CATEGORY.JunimoBundle;
|
||||
}
|
||||
|
||||
if (toReturn == "")
|
||||
return (null, category);
|
||||
|
||||
return (toReturn, category);
|
||||
}
|
||||
|
||||
///<summary>Returns the name of the object at tile</summary>
|
||||
public static string? getNameAtTile(Vector2 tile)
|
||||
{
|
||||
int x = (int)tile.X;
|
||||
int y = (int)tile.Y;
|
||||
string? toReturn = "";
|
||||
|
||||
bool isColliding = isCollidingAtTile(x, y);
|
||||
Dictionary<Vector2, Netcode.NetRef<TerrainFeature>> terrainFeature = Game1.currentLocation.terrainFeatures.FieldDict;
|
||||
string? door = getDoorAtTile(x, y);
|
||||
(CATEGORY?, string?) tileInfo = getTileInfo(x, y);
|
||||
string? junimoBundle = getJunimoBundleAt(x, y);
|
||||
string? resourceClump = getResourceClumpAtTile(x, y);
|
||||
string? farmAnimal = getFarmAnimalAt(Game1.currentLocation, x, y);
|
||||
|
||||
if (Game1.currentLocation.isCharacterAtTile(tile) != null)
|
||||
{
|
||||
NPC npc = Game1.currentLocation.isCharacterAtTile(tile);
|
||||
toReturn = npc.displayName;
|
||||
}
|
||||
else if (farmAnimal != null)
|
||||
{
|
||||
toReturn = farmAnimal;
|
||||
}
|
||||
else if (Game1.currentLocation.isWaterTile(x, y) && isColliding)
|
||||
{
|
||||
toReturn = "Water";
|
||||
}
|
||||
else if (Game1.currentLocation.isObjectAtTile(x, y))
|
||||
{
|
||||
toReturn = getObjectAtTile(x, y).Item1;
|
||||
}
|
||||
else if (terrainFeature.ContainsKey(tile))
|
||||
{
|
||||
string? terrain = getTerrainFeatureAtTile(terrainFeature[tile]).Item1;
|
||||
if (terrain != null)
|
||||
toReturn = terrain;
|
||||
}
|
||||
else if (Game1.currentLocation.getLargeTerrainFeatureAt(x, y) != null)
|
||||
{
|
||||
toReturn = getBushAtTile(x, y);
|
||||
}
|
||||
else if (resourceClump != null)
|
||||
{
|
||||
toReturn = resourceClump;
|
||||
}
|
||||
else if (door != null)
|
||||
{
|
||||
toReturn = door;
|
||||
}
|
||||
else if (isMineDownLadderAtTile(x, y))
|
||||
{
|
||||
toReturn = "Ladder";
|
||||
}
|
||||
else if (isMineUpLadderAtTile(x, y))
|
||||
{
|
||||
toReturn = "Up Ladder";
|
||||
}
|
||||
else if (isElevatorAtTile(x, y))
|
||||
{
|
||||
toReturn = "Elevator";
|
||||
}
|
||||
else if (tileInfo.Item2 != null)
|
||||
{
|
||||
toReturn = tileInfo.Item2;
|
||||
}
|
||||
else if (junimoBundle != null)
|
||||
{
|
||||
toReturn = junimoBundle;
|
||||
}
|
||||
|
||||
if (toReturn == "")
|
||||
return null;
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public static string? getBushAtTile(int x, int y)
|
||||
{
|
||||
string? toReturn = null;
|
||||
Bush bush = (Bush)Game1.currentLocation.getLargeTerrainFeatureAt(x, y);
|
||||
int size = bush.size;
|
||||
|
||||
#region Check if bush is harvestable or not
|
||||
if (!bush.townBush && (int)bush.tileSheetOffset == 1 && bush.inBloom(Game1.GetSeasonForLocation(Game1.currentLocation), Game1.dayOfMonth))
|
||||
{
|
||||
// Taken from the game's code
|
||||
string season = ((int)bush.overrideSeason == -1) ? Game1.GetSeasonForLocation(Game1.currentLocation) : Utility.getSeasonNameFromNumber(bush.overrideSeason);
|
||||
int shakeOff = -1;
|
||||
if (!(season == "spring"))
|
||||
{
|
||||
if (season == "fall")
|
||||
{
|
||||
shakeOff = 410;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shakeOff = 296;
|
||||
}
|
||||
if ((int)size == 3)
|
||||
{
|
||||
shakeOff = 815;
|
||||
}
|
||||
if ((int)size == 4)
|
||||
{
|
||||
shakeOff = 73;
|
||||
}
|
||||
if (shakeOff == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
toReturn = "Harvestable";
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (bush.townBush)
|
||||
toReturn = $"{toReturn} Town Bush";
|
||||
else if (bush.greenhouseBush)
|
||||
toReturn = $"{toReturn} Greenhouse Bush";
|
||||
else
|
||||
toReturn = $"{toReturn} Bush";
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public static string? getJunimoBundleAt(int x, int y)
|
||||
{
|
||||
if (Game1.currentLocation is not CommunityCenter)
|
||||
return null;
|
||||
|
||||
CommunityCenter communityCenter = ((CommunityCenter)Game1.currentLocation);
|
||||
|
||||
string? name = (x, y) switch
|
||||
{
|
||||
(14, 5) => "Pantry",
|
||||
(14, 23) => "Crafts Room",
|
||||
(40, 10) => "Fish Tank",
|
||||
(63, 14) => "Boiler Room",
|
||||
(55, 6) => "Vault",
|
||||
(46, 11) => "Bulletin Board",
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (name != null && communityCenter.shouldNoteAppearInArea(CommunityCenter.getAreaNumberFromName(name)))
|
||||
return $"{name} bundle";
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool isCollidingAtTile(int x, int y)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Game1.currentLocation is Woods && getStumpsInWoods(x, y) != null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string? getFarmAnimalAt(GameLocation? location, int x, int y, bool onlyName = false)
|
||||
{
|
||||
if (location == null)
|
||||
return null;
|
||||
|
||||
if (location is not Farm && location is not AnimalHouse)
|
||||
return null;
|
||||
|
||||
List<FarmAnimal>? farmAnimals = null;
|
||||
|
||||
if (location is Farm)
|
||||
farmAnimals = ((Farm)location).getAllFarmAnimals();
|
||||
else if (location is AnimalHouse)
|
||||
farmAnimals = ((AnimalHouse)location).animals.Values.ToList();
|
||||
|
||||
if (farmAnimals == null || farmAnimals.Count <= 0)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < farmAnimals.Count; i++)
|
||||
{
|
||||
int fx = farmAnimals[i].getTileX();
|
||||
int fy = farmAnimals[i].getTileY();
|
||||
|
||||
if (fx.Equals(x) && fy.Equals(y))
|
||||
{
|
||||
string name = farmAnimals[i].displayName;
|
||||
int age = farmAnimals[i].age.Value;
|
||||
string type = farmAnimals[i].displayType;
|
||||
|
||||
if (onlyName)
|
||||
return name;
|
||||
|
||||
return $"{name}, {type}, age {age}";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns>Item1: This is the category of the tile. Default to Furnitures.
|
||||
/// <br/>Item2: This is the name of the tile. Default to null if the tile tile has nothing on it.</returns>
|
||||
public static (CATEGORY?, string?) getTileInfo(int x, int y)
|
||||
{
|
||||
|
||||
int? index = null;
|
||||
|
||||
if (Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y] != null)
|
||||
index = Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y].TileIndex;
|
||||
/* Add More
|
||||
MainClass.monitor.Log(index.ToString(), LogLevel.Debug);
|
||||
*/
|
||||
|
||||
if (Game1.currentLocation is Farm)
|
||||
{
|
||||
Building building = ((Farm)Game1.currentLocation).getBuildingAt(new Vector2(x, y));
|
||||
if (building != null)
|
||||
{
|
||||
return (CATEGORY.Buildings, building.buildingType.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (index != null)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 1955:
|
||||
case 41:
|
||||
return (CATEGORY.Furnitures, "Mail Box");
|
||||
case 1003:
|
||||
return (CATEGORY.Furnitures, "Street lamp");
|
||||
case 78:
|
||||
return (CATEGORY.Furnitures, "Trash bin");
|
||||
case 617:
|
||||
return (CATEGORY.Furnitures, "Daily quest");
|
||||
case 616:
|
||||
return (CATEGORY.Furnitures, "Calender");
|
||||
}
|
||||
|
||||
if (Game1.currentLocation is FarmHouse || Game1.currentLocation is IslandFarmHouse)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 173:
|
||||
return (CATEGORY.Furnitures, "Fridge");
|
||||
case 169:
|
||||
case 170:
|
||||
case 171:
|
||||
case 172:
|
||||
return (CATEGORY.Furnitures, "Kitchen");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
public static (string?, CATEGORY) getTerrainFeatureAtTile(Netcode.NetRef<TerrainFeature> terrain)
|
||||
{
|
||||
string? toReturn = null;
|
||||
CATEGORY category = CATEGORY.Others;
|
||||
|
||||
if (terrain.Get() is HoeDirt)
|
||||
{
|
||||
category = CATEGORY.Crops;
|
||||
HoeDirt dirt = (HoeDirt)terrain.Get();
|
||||
if (dirt.crop != null)
|
||||
{
|
||||
string cropName = Game1.objectInformation[dirt.crop.indexOfHarvest].Split('/')[0];
|
||||
toReturn = $"{cropName}";
|
||||
|
||||
bool isWatered = dirt.state.Value == HoeDirt.watered;
|
||||
bool isHarvestable = dirt.readyForHarvest();
|
||||
bool isFertilized = dirt.fertilizer.Value != HoeDirt.noFertilizer;
|
||||
|
||||
if (isWatered)
|
||||
toReturn = "Watered " + toReturn;
|
||||
|
||||
if (isFertilized)
|
||||
toReturn = "Fertilized " + toReturn;
|
||||
|
||||
if (isHarvestable)
|
||||
toReturn = "Harvestable " + toReturn;
|
||||
}
|
||||
else
|
||||
{
|
||||
toReturn = "Soil";
|
||||
bool isWatered = dirt.state.Value == HoeDirt.watered;
|
||||
bool isFertilized = dirt.fertilizer.Value != HoeDirt.noFertilizer;
|
||||
|
||||
if (isWatered)
|
||||
toReturn = "Watered " + toReturn;
|
||||
|
||||
if (isFertilized)
|
||||
toReturn = "Fertilized " + toReturn;
|
||||
}
|
||||
}
|
||||
else if (terrain.Get() is GiantCrop)
|
||||
{
|
||||
category = CATEGORY.Crops;
|
||||
int whichCrop = ((GiantCrop)terrain.Get()).which.Value;
|
||||
switch (whichCrop)
|
||||
{
|
||||
case 0:
|
||||
toReturn = "Cauliflower";
|
||||
break;
|
||||
case 1:
|
||||
toReturn = "Melon";
|
||||
break;
|
||||
case 2:
|
||||
toReturn = "Pumpkin";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (terrain.Get() is CosmeticPlant)
|
||||
{
|
||||
category = CATEGORY.Furnitures;
|
||||
CosmeticPlant cosmeticPlant = (CosmeticPlant)terrain.Get();
|
||||
toReturn = cosmeticPlant.textureName().ToLower();
|
||||
|
||||
if (toReturn.Contains("terrain"))
|
||||
toReturn.Replace("terrain", "");
|
||||
|
||||
if (toReturn.Contains("feature"))
|
||||
toReturn.Replace("feature", "");
|
||||
}
|
||||
else if (terrain.Get() is Flooring)
|
||||
{
|
||||
category = CATEGORY.Flooring;
|
||||
Flooring flooring = (Flooring)terrain.Get();
|
||||
bool isPathway = flooring.isPathway.Get();
|
||||
bool isSteppingStone = flooring.isSteppingStone.Get();
|
||||
|
||||
toReturn = "Flooring";
|
||||
|
||||
if (isPathway)
|
||||
toReturn = "Pathway";
|
||||
|
||||
if (isSteppingStone)
|
||||
toReturn = "Stepping Stone";
|
||||
}
|
||||
else if (terrain.Get() is FruitTree)
|
||||
{
|
||||
category = CATEGORY.Trees;
|
||||
toReturn = getFruitTree((FruitTree)terrain.Get());
|
||||
}
|
||||
else if (terrain.Get() is Grass)
|
||||
{
|
||||
category = CATEGORY.Debris;
|
||||
toReturn = "Grass";
|
||||
}
|
||||
else if (terrain.Get() is Tree)
|
||||
{
|
||||
category = CATEGORY.Trees;
|
||||
toReturn = getTree((Tree)terrain.Get());
|
||||
}
|
||||
else if (terrain.Get() is Quartz)
|
||||
{
|
||||
category = CATEGORY.MineItems;
|
||||
toReturn = "Quartz";
|
||||
}
|
||||
|
||||
return (toReturn, category);
|
||||
}
|
||||
|
||||
public static string getFruitTree(FruitTree fruitTree)
|
||||
{
|
||||
int stage = fruitTree.growthStage.Value;
|
||||
int fruitIndex = fruitTree.indexOfFruit.Get();
|
||||
|
||||
string toReturn = Game1.objectInformation[fruitIndex].Split('/')[0];
|
||||
|
||||
if (stage == 0)
|
||||
toReturn = $"{toReturn} seed";
|
||||
else if (stage == 1)
|
||||
toReturn = $"{toReturn} sprout";
|
||||
else if (stage == 2)
|
||||
toReturn = $"{toReturn} sapling";
|
||||
else if (stage == 3)
|
||||
toReturn = $"{toReturn} bush";
|
||||
else if (stage >= 4)
|
||||
toReturn = $"{toReturn} tree";
|
||||
|
||||
if (fruitTree.fruitsOnTree.Value > 0)
|
||||
toReturn = $"Harvestable {toReturn}";
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public static string getTree(Tree tree)
|
||||
{
|
||||
int treeType = tree.treeType.Value;
|
||||
int treeStage = tree.growthStage.Value;
|
||||
string treeName = "tree";
|
||||
string seedName = "";
|
||||
|
||||
// Return with the name if it's one of the 3 special trees
|
||||
switch (treeType)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
return "Winter Tree";
|
||||
case 6:
|
||||
return "Palm Tree";
|
||||
case 7:
|
||||
return "Mushroom Tree";
|
||||
}
|
||||
|
||||
|
||||
if (treeType <= 3)
|
||||
seedName = Game1.objectInformation[308 + treeType].Split('/')[0];
|
||||
else if (treeType == 8)
|
||||
seedName = Game1.objectInformation[292].Split('/')[0];
|
||||
|
||||
if (treeStage >= 1)
|
||||
{
|
||||
switch (seedName.ToLower())
|
||||
{
|
||||
case "mahogany seed":
|
||||
treeName = "Mahogany";
|
||||
break;
|
||||
case "acorn":
|
||||
treeName = "Oak";
|
||||
break;
|
||||
case "maple seed":
|
||||
treeName = "Maple";
|
||||
break;
|
||||
case "pine cone":
|
||||
treeName = "Pine";
|
||||
break;
|
||||
}
|
||||
|
||||
if (treeStage == 1)
|
||||
treeName = $"{treeName} sprout";
|
||||
else if (treeStage == 2)
|
||||
treeName = $"{treeName} sapling";
|
||||
else if (treeStage == 3 || treeStage == 4)
|
||||
treeName = $"{treeName} bush";
|
||||
else if (treeStage >= 5)
|
||||
treeName = $"{treeName} tree";
|
||||
|
||||
return treeName;
|
||||
}
|
||||
|
||||
return seedName;
|
||||
}
|
||||
|
||||
public static (string?, CATEGORY) getObjectAtTile(int x, int y)
|
||||
{
|
||||
string? toReturn = null;
|
||||
|
||||
StardewValley.Object obj = Game1.currentLocation.getObjectAtTile(x, y);
|
||||
int index = obj.ParentSheetIndex;
|
||||
toReturn = obj.DisplayName;
|
||||
|
||||
// Get object names based on index
|
||||
switch (index)
|
||||
{
|
||||
case 313:
|
||||
case 314:
|
||||
case 315:
|
||||
case 316:
|
||||
case 317:
|
||||
case 318:
|
||||
case 452:
|
||||
case 674:
|
||||
case 675:
|
||||
case 676:
|
||||
case 677:
|
||||
case 678:
|
||||
case 679:
|
||||
case 750:
|
||||
case 784:
|
||||
case 785:
|
||||
case 786:
|
||||
return ("Weed", CATEGORY.Debris);
|
||||
case 792:
|
||||
case 793:
|
||||
case 794:
|
||||
return ("Fertile weed", CATEGORY.Debris);
|
||||
case 319:
|
||||
case 320:
|
||||
case 321:
|
||||
return ("Ice crystal", CATEGORY.Debris);
|
||||
case 75:
|
||||
return ("Geode", CATEGORY.MineItems);
|
||||
case 32:
|
||||
case 34:
|
||||
case 36:
|
||||
case 38:
|
||||
case 40:
|
||||
case 42:
|
||||
case 48:
|
||||
case 50:
|
||||
case 52:
|
||||
case 54:
|
||||
case 56:
|
||||
case 58:
|
||||
return ("Coloured stone", CATEGORY.Debris);
|
||||
case 668:
|
||||
case 670:
|
||||
case 845:
|
||||
case 846:
|
||||
case 847:
|
||||
return ("Mine stone", CATEGORY.MineItems);
|
||||
case 818:
|
||||
return ("Clay stone", CATEGORY.Debris);
|
||||
case 816:
|
||||
case 817:
|
||||
return ("Fossil stone", CATEGORY.Debris);
|
||||
case 118:
|
||||
case 120:
|
||||
case 122:
|
||||
case 124:
|
||||
return ("Barrel", CATEGORY.MineItems);
|
||||
case 119:
|
||||
case 121:
|
||||
case 123:
|
||||
case 125:
|
||||
return ("Item box", CATEGORY.MineItems);
|
||||
}
|
||||
|
||||
if (Game1.currentLocation is Mine or MineShaft)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 76:
|
||||
return ("Frozen geode", CATEGORY.MineItems);
|
||||
case 77:
|
||||
return ("Magma geode", CATEGORY.MineItems);
|
||||
case 8:
|
||||
case 66:
|
||||
return ("Amethyst node", CATEGORY.MineItems);
|
||||
case 14:
|
||||
case 62:
|
||||
return ("Aquamarine node", CATEGORY.MineItems);
|
||||
case 843:
|
||||
case 844:
|
||||
return ("Cinder shard node", CATEGORY.MineItems);
|
||||
case 2:
|
||||
case 72:
|
||||
return ("Diamond node", CATEGORY.MineItems);
|
||||
case 12:
|
||||
case 60:
|
||||
return ("Emerald node", CATEGORY.MineItems);
|
||||
case 44:
|
||||
return ("Gem node", CATEGORY.MineItems);
|
||||
case 6:
|
||||
case 70:
|
||||
return ("Jade node", CATEGORY.MineItems);
|
||||
case 46:
|
||||
return ("Mystic stone", CATEGORY.MineItems);
|
||||
case 74:
|
||||
return ("Prismatic node", CATEGORY.MineItems);
|
||||
case 4:
|
||||
case 64:
|
||||
return ("Ruby node", CATEGORY.MineItems);
|
||||
case 10:
|
||||
case 68:
|
||||
return ("Topaz node", CATEGORY.MineItems);
|
||||
case 819:
|
||||
return ("Omni geode node", CATEGORY.MineItems);
|
||||
case 751:
|
||||
case 849:
|
||||
return ("Copper node", CATEGORY.MineItems);
|
||||
case 764:
|
||||
return ("Gold node", CATEGORY.MineItems);
|
||||
case 765:
|
||||
return ("Iridium node", CATEGORY.MineItems);
|
||||
case 290:
|
||||
case 850:
|
||||
return ("Iron node", CATEGORY.MineItems);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj is Chest)
|
||||
{
|
||||
Chest chest = (Chest)obj;
|
||||
return (chest.DisplayName, CATEGORY.Chests);
|
||||
}
|
||||
|
||||
if (obj is Furniture)
|
||||
return (toReturn, CATEGORY.Furnitures);
|
||||
|
||||
if (toReturn != null)
|
||||
return (toReturn, CATEGORY.Others);
|
||||
|
||||
return (null, CATEGORY.Others);
|
||||
}
|
||||
|
||||
public static bool isMineDownLadderAtTile(int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Game1.currentLocation is Mine or MineShaft)
|
||||
{
|
||||
int? index = 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) { }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool isMineUpLadderAtTile(int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Game1.currentLocation is Mine or MineShaft)
|
||||
{
|
||||
int? index = null;
|
||||
|
||||
if (Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y] != null)
|
||||
index = Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y].TileIndex;
|
||||
|
||||
if (index == 115)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool isElevatorAtTile(int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Game1.currentLocation is Mine or MineShaft)
|
||||
{
|
||||
int? index = null;
|
||||
|
||||
if (Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y] != null)
|
||||
index = Game1.currentLocation.Map.GetLayer("Buildings").Tiles[x, y].TileIndex;
|
||||
|
||||
if (index == 112)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string? getDoorAtTile(int x, int y)
|
||||
{
|
||||
Point tilePoint = new Point(x, y);
|
||||
StardewValley.Network.NetPointDictionary<string, Netcode.NetString> doorList = Game1.currentLocation.doors;
|
||||
|
||||
for (int i = 0; i < doorList.Count(); i++)
|
||||
{
|
||||
if (doorList.ContainsKey(tilePoint))
|
||||
{
|
||||
string? doorName;
|
||||
doorList.TryGetValue(tilePoint, out doorName);
|
||||
|
||||
if (doorName != null)
|
||||
return $"{doorName} door";
|
||||
else
|
||||
return "door";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string? getResourceClumpAtTile(int x, int y)
|
||||
{
|
||||
if (Game1.currentLocation is Woods)
|
||||
return getStumpsInWoods(x, y);
|
||||
|
||||
for (int i = 0; i < Game1.currentLocation.resourceClumps.Count; i++)
|
||||
{
|
||||
if (Game1.currentLocation.resourceClumps[i].occupiesTile(x, y))
|
||||
{
|
||||
int index = Game1.currentLocation.resourceClumps[i].parentSheetIndex;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 600:
|
||||
return "Large Stump";
|
||||
case 602:
|
||||
return "Hollow Log";
|
||||
case 622:
|
||||
return "Meteorite";
|
||||
case 752:
|
||||
case 754:
|
||||
case 756:
|
||||
case 758:
|
||||
return "Mine Rock";
|
||||
case 672:
|
||||
return "Boulder";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string? getStumpsInWoods(int x, int y)
|
||||
{
|
||||
if (Game1.currentLocation is not Woods)
|
||||
return null;
|
||||
|
||||
if ((x == 8 || x == 9) && y == 7)
|
||||
{
|
||||
return "Old Master Cannoli";
|
||||
}
|
||||
Netcode.NetObjectList<ResourceClump> stumps = ((Woods)Game1.currentLocation).stumps;
|
||||
for (int i = 0; i < stumps.Count; i++)
|
||||
{
|
||||
if (stumps[i].occupiesTile(x, y))
|
||||
{
|
||||
return "Large Stump";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
177
stardew-access/Features/StaticTiles.cs
Normal file
177
stardew-access/Features/StaticTiles.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using StardewValley;
|
||||
|
||||
namespace stardew_access.Features
|
||||
{
|
||||
public class StaticTiles
|
||||
{
|
||||
private JObject? staticTilesData = null;
|
||||
private JObject? customTilesData = null;
|
||||
|
||||
public StaticTiles()
|
||||
{
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamReader file = new StreamReader(Path.Combine(MainClass.ModHelper.DirectoryPath, "assets", "static-tiles.json")))
|
||||
{
|
||||
string json = file.ReadToEnd();
|
||||
staticTilesData = JObject.Parse(json);
|
||||
}
|
||||
|
||||
MainClass.InfoLog($"Loaded static-tile.json");
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
MainClass.ErrorLog($"static-tiles.json file not found or an error occured while initializing static-tiles.json\nThe path of the file should be:\n\t{Path.Combine(MainClass.ModHelper.DirectoryPath, "assets", "static-tiles.json")}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamReader file = new StreamReader(Path.Combine(MainClass.ModHelper.DirectoryPath, "assets", "custom-tiles.json")))
|
||||
{
|
||||
string json = file.ReadToEnd();
|
||||
customTilesData = JObject.Parse(json);
|
||||
}
|
||||
|
||||
MainClass.InfoLog($"Loaded custom-tile.json");
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
MainClass.ErrorLog($"custom-tiles.json file not found or an error occured while initializing custom-tiles.json\nThe path of the file should be:\n\t{Path.Combine(MainClass.ModHelper.DirectoryPath, "assets", "custom-tiles.json")}");
|
||||
}
|
||||
}
|
||||
|
||||
public bool isAvailable(string locationName)
|
||||
{
|
||||
List<JObject> allData = new List<JObject>();
|
||||
|
||||
if (customTilesData != null) allData.Add(customTilesData);
|
||||
if (staticTilesData != null) allData.Add(staticTilesData);
|
||||
|
||||
foreach (JObject data in allData)
|
||||
{
|
||||
foreach (KeyValuePair<string, JToken?> location in data)
|
||||
{
|
||||
if (location.Key.Contains("||") && MainClass.ModHelper != null)
|
||||
{
|
||||
string uniqueModID = location.Key.Substring(location.Key.LastIndexOf("||") + 2);
|
||||
string locationNameInJson = location.Key.Remove(location.Key.LastIndexOf("||"));
|
||||
bool isLoaded = MainClass.ModHelper.ModRegistry.IsLoaded(uniqueModID);
|
||||
|
||||
if (!isLoaded) continue; // Skip if the specified mod is not loaded
|
||||
if (locationName.ToLower().Equals(locationNameInJson.ToLower())) return true;
|
||||
}
|
||||
else if (locationName.ToLower().Equals(location.Key.ToLower()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string? getStaticTileInfoAt(int x, int y)
|
||||
{
|
||||
return getStaticTileInfoAtWithCategory(x, y).name;
|
||||
}
|
||||
|
||||
public (string? name, CATEGORY category) getStaticTileInfoAtWithCategory(int x, int y)
|
||||
{
|
||||
List<JObject> allData = new List<JObject>();
|
||||
|
||||
if (customTilesData != null) allData.Add(customTilesData);
|
||||
if (staticTilesData != null) allData.Add(staticTilesData);
|
||||
|
||||
foreach (JObject data in allData)
|
||||
{
|
||||
foreach (KeyValuePair<string, JToken?> location in data)
|
||||
{
|
||||
if (location.Key.Contains("||") && MainClass.ModHelper != null)
|
||||
{
|
||||
// Mod Specific Tiles
|
||||
// We can add tiles that only get detected when the specified mod is loaded.
|
||||
// Syntax: <location name>||<Mod's unique id, look into the mod's manifest.json for unique id>
|
||||
// Example: THe following tile will only be detected if Stardew Valley Expanded mod is installed
|
||||
// {
|
||||
// .
|
||||
// .
|
||||
// .
|
||||
// "Town||FlashShifter.StardewValleyExpandedCP":{
|
||||
// "<Tile Name>":{
|
||||
// "x": [<x location(s)>],
|
||||
// "y": [<y location(s)>],
|
||||
// "type": "<Category name>"
|
||||
// }
|
||||
// },
|
||||
// .
|
||||
// .
|
||||
// .
|
||||
// }
|
||||
string uniqueModID = location.Key.Substring(location.Key.LastIndexOf("||") + 2);
|
||||
string locationName = location.Key.Remove(location.Key.LastIndexOf("||"));
|
||||
bool isLoaded = MainClass.ModHelper.ModRegistry.IsLoaded(uniqueModID);
|
||||
|
||||
if (!isLoaded) continue; // Skip if the specified mod is not loaded
|
||||
if (!Game1.currentLocation.Name.ToLower().Equals(locationName.ToLower())) continue;
|
||||
}
|
||||
else if (!Game1.currentLocation.Name.ToLower().Equals(location.Key.ToLower())) continue;
|
||||
|
||||
if (location.Value != null)
|
||||
foreach (var tile in ((JObject)location.Value))
|
||||
{
|
||||
if (tile.Value == null)
|
||||
continue;
|
||||
|
||||
JToken? tileXArray = tile.Value["x"];
|
||||
JToken? tileYArray = tile.Value["y"];
|
||||
JToken? tileType = tile.Value["type"];
|
||||
|
||||
if (tileXArray == null || tileYArray == null || tileType == null)
|
||||
continue;
|
||||
|
||||
bool isXPresent = false;
|
||||
bool isYPresent = false;
|
||||
|
||||
foreach (var item in tileXArray)
|
||||
{
|
||||
if (short.Parse(item.ToString()) == x)
|
||||
{
|
||||
isXPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in tileYArray)
|
||||
{
|
||||
if (short.Parse(item.ToString()) == y)
|
||||
{
|
||||
isYPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isXPresent && isYPresent)
|
||||
{
|
||||
string key = tile.Key;
|
||||
if (key.Contains('[') && key.Contains(']'))
|
||||
{
|
||||
int i1 = key.IndexOf('[');
|
||||
int i2 = key.LastIndexOf(']');
|
||||
|
||||
if (i1 < i2)
|
||||
{
|
||||
key = key.Remove(i1, ++i2 - i1);
|
||||
}
|
||||
}
|
||||
|
||||
return (key.Trim(), CATEGORY.FromString(tileType.ToString().ToLower()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (null, CATEGORY.Others);
|
||||
}
|
||||
}
|
||||
}
|
1327
stardew-access/Features/TileInfo.cs
Normal file
1327
stardew-access/Features/TileInfo.cs
Normal file
File diff suppressed because it is too large
Load Diff
291
stardew-access/Features/TileViewer.cs
Normal file
291
stardew-access/Features/TileViewer.cs
Normal file
@@ -0,0 +1,291 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using xTile;
|
||||
using StardewValley;
|
||||
using StardewValley.Menus;
|
||||
|
||||
namespace stardew_access.Features
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Allows browsing of the map and snapping mouse to tiles with the arrow keys
|
||||
/// </summary>
|
||||
public class TileViewer
|
||||
{
|
||||
|
||||
//None of these positions take viewport into account; other functions are responsible later
|
||||
private Vector2 ViewingOffset = Vector2.Zero;
|
||||
private Vector2 relativeOffsetLockPosition = Vector2.Zero;
|
||||
private Boolean relativeOffsetLock = false;
|
||||
private Vector2 prevPlayerPosition = Vector2.Zero, prevFacing = Vector2.Zero;
|
||||
private Vector2 finalTile = Vector2.Zero;
|
||||
private Vector2 prevTile = Vector2.Zero;
|
||||
|
||||
public Boolean isAutoWalking = false;
|
||||
|
||||
private Vector2 PlayerFacingVector
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Game1.player.FacingDirection)
|
||||
{
|
||||
case 0:
|
||||
return new Vector2(0, -Game1.tileSize);
|
||||
case 1:
|
||||
return new Vector2(Game1.tileSize, 0);
|
||||
case 2:
|
||||
return new Vector2(0, Game1.tileSize);
|
||||
case 3:
|
||||
return new Vector2(-Game1.tileSize, 0);
|
||||
default:
|
||||
return Vector2.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 PlayerPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
int x = Game1.player.GetBoundingBox().Center.X;
|
||||
int y = Game1.player.GetBoundingBox().Center.Y;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the position of the tile cursor in pixels from the upper-left corner of the map.
|
||||
/// </summary>
|
||||
/// <returns>Vector2</returns>
|
||||
public Vector2 GetTileCursorPosition()
|
||||
{
|
||||
Vector2 target = this.PlayerPosition;
|
||||
if (this.relativeOffsetLock)
|
||||
{
|
||||
target += this.relativeOffsetLockPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
target += this.PlayerFacingVector + this.ViewingOffset;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the tile at the position of the tile cursor.
|
||||
/// </summary>
|
||||
/// <returns>Vector2</returns>
|
||||
public Vector2 GetViewingTile()
|
||||
{
|
||||
Vector2 position = this.GetTileCursorPosition();
|
||||
return new Vector2((int)position.X / Game1.tileSize, (int)position.Y / Game1.tileSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle keyboard input related to the tile viewer.
|
||||
/// </summary>
|
||||
public void HandleInput()
|
||||
{
|
||||
if (MainClass.Config.ToggleRelativeCursorLockKey.JustPressed())
|
||||
{
|
||||
this.relativeOffsetLock = !this.relativeOffsetLock;
|
||||
if (this.relativeOffsetLock)
|
||||
{
|
||||
this.relativeOffsetLockPosition = this.PlayerFacingVector + this.ViewingOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.relativeOffsetLockPosition = Vector2.Zero;
|
||||
}
|
||||
MainClass.ScreenReader.Say("Relative cursor lock " + (this.relativeOffsetLock ? "enabled" : "disabled") + ".", true);
|
||||
}
|
||||
else if (MainClass.Config.TileCursorPreciseUpKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(0, -MainClass.Config.TileCursorPreciseMovementDistance), true);
|
||||
}
|
||||
else if (MainClass.Config.TileCursorPreciseRightKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(MainClass.Config.TileCursorPreciseMovementDistance, 0), true);
|
||||
}
|
||||
else if (MainClass.Config.TileCursorPreciseDownKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(0, MainClass.Config.TileCursorPreciseMovementDistance), true);
|
||||
}
|
||||
else if (MainClass.Config.TileCursorPreciseLeftKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(-MainClass.Config.TileCursorPreciseMovementDistance, 0), true);
|
||||
}
|
||||
else if (MainClass.Config.TileCursorUpKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(0, -Game1.tileSize));
|
||||
}
|
||||
else if (MainClass.Config.TileCursorRightKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(Game1.tileSize, 0));
|
||||
}
|
||||
else if (MainClass.Config.TileCursorDownKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(0, Game1.tileSize));
|
||||
}
|
||||
else if (MainClass.Config.TileCursorLeftKey.JustPressed())
|
||||
{
|
||||
this.cursorMoveInput(new Vector2(-Game1.tileSize, 0));
|
||||
}
|
||||
else if (MainClass.Config.AutoWalkToTileKey.JustPressed() && StardewModdingAPI.Context.IsPlayerFree)
|
||||
{
|
||||
this.startAutoWalking();
|
||||
}
|
||||
}
|
||||
|
||||
private void startAutoWalking()
|
||||
{
|
||||
PathFindController controller = new PathFindController(Game1.player, Game1.currentLocation, this.GetViewingTile().ToPoint(), Game1.player.FacingDirection);
|
||||
controller.allowPlayerPathingInEvent = true;
|
||||
if (controller.pathToEndPoint != null && controller.pathToEndPoint.Count > 0)
|
||||
{
|
||||
Game1.player.controller = controller;
|
||||
this.isAutoWalking = true;
|
||||
this.finalTile = this.GetViewingTile();
|
||||
MainClass.ReadTileFeature.pause();
|
||||
MainClass.ScreenReader.Say($"Moving to {this.finalTile.X}x {this.finalTile.Y}y", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.ScreenReader.Say($"Cannot move to {this.finalTile.X}x {this.finalTile.Y}y", true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the auto walk controller and reset variables
|
||||
/// </summary>
|
||||
/// <param name="wasForced">Narrates a message if set to true.</param>
|
||||
public void stopAutoWalking(bool wasForced = false)
|
||||
{
|
||||
this.finalTile = Vector2.Zero;
|
||||
this.isAutoWalking = false;
|
||||
Game1.player.controller = null;
|
||||
MainClass.ReadTileFeature.resume();
|
||||
if (wasForced)
|
||||
MainClass.ScreenReader.Say("Stopped moving", true);
|
||||
}
|
||||
|
||||
private void cursorMoveInput(Vector2 delta, Boolean precise = false)
|
||||
{
|
||||
if (!tryMoveTileView(delta)) return;
|
||||
Vector2 position = this.GetTileCursorPosition();
|
||||
Vector2 tile = this.GetViewingTile();
|
||||
String? name = TileInfo.getNameAtTile(tile);
|
||||
|
||||
// Prepend the player's name if the viewing tile is occupied by the player itself
|
||||
if (CurrentPlayer.PositionX == tile.X && CurrentPlayer.PositionY == tile.Y)
|
||||
{
|
||||
name = $"{Game1.player.displayName}, {name}";
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
// Report if a tile is empty or blocked if there is nothing on it
|
||||
if (TileInfo.isCollidingAtTile((int)tile.X, (int)tile.Y))
|
||||
{
|
||||
name = "blocked";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "empty";
|
||||
}
|
||||
}
|
||||
if (precise)
|
||||
{
|
||||
MainClass.ScreenReader.Say($"{name}, {position.X}, {position.Y}", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.ScreenReader.Say($"{name}, {(int)(position.X / Game1.tileSize)}, {(int)(position.Y / Game1.tileSize)}", true);
|
||||
}
|
||||
}
|
||||
|
||||
private bool tryMoveTileView(Vector2 delta)
|
||||
{
|
||||
Vector2 dest = this.GetTileCursorPosition() + delta;
|
||||
if (!isPositionOnMap(dest)) return false;
|
||||
if ((MainClass.Config.LimitTileCursorToScreen && Utility.isOnScreen(dest, 0)) || !MainClass.Config.LimitTileCursorToScreen)
|
||||
{
|
||||
if (this.relativeOffsetLock)
|
||||
{
|
||||
this.relativeOffsetLockPosition += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ViewingOffset += delta;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SnapMouseToPlayer()
|
||||
{
|
||||
Vector2 cursorPosition = this.GetTileCursorPosition();
|
||||
if (allowMouseSnap(cursorPosition))
|
||||
// Must account for viewport here
|
||||
Game1.setMousePosition((int)cursorPosition.X - Game1.viewport.X, (int)cursorPosition.Y - Game1.viewport.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle tile viewer logic.
|
||||
/// </summary>
|
||||
public void update()
|
||||
{
|
||||
//Reset the viewing cursor to the player when they turn or move. This will not reset the locked offset relative cursor position.
|
||||
if (this.prevFacing != this.PlayerFacingVector || this.prevPlayerPosition != this.PlayerPosition)
|
||||
{
|
||||
this.ViewingOffset = Vector2.Zero;
|
||||
}
|
||||
this.prevFacing = this.PlayerFacingVector;
|
||||
this.prevPlayerPosition = this.PlayerPosition;
|
||||
if (MainClass.Config.SnapMouse)
|
||||
this.SnapMouseToPlayer();
|
||||
|
||||
if (this.isAutoWalking)
|
||||
{
|
||||
if (Vector2.Distance(this.prevTile, CurrentPlayer.Position) >= 2f)
|
||||
{
|
||||
prevTile = CurrentPlayer.Position;
|
||||
Game1.player.checkForFootstep();
|
||||
}
|
||||
|
||||
if (this.finalTile != Vector2.Zero && this.finalTile == CurrentPlayer.Position)
|
||||
{
|
||||
MainClass.ScreenReader.Say("Reached destination", true);
|
||||
this.stopAutoWalking();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static bool allowMouseSnap(Vector2 point)
|
||||
{
|
||||
// Utility.isOnScreen treats a vector as a pixel position, not a tile position
|
||||
if (!Utility.isOnScreen(point, 0)) return false;
|
||||
|
||||
//prevent mousing over the toolbar or any other UI component with the tile cursor
|
||||
foreach (IClickableMenu menu in Game1.onScreenMenus)
|
||||
{
|
||||
//must account for viewport here
|
||||
if (menu.isWithinBounds((int)point.X - Game1.viewport.X, (int)point.Y - Game1.viewport.Y)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool isPositionOnMap(Vector2 position)
|
||||
{
|
||||
// Check whether the position is a warp point, if so then return true, sometimes warp points are 1 tile off the map for example in coops and barns
|
||||
if (TileInfo.isWarpPointAtTile((int)(position.X / Game1.tileSize), (int)(position.Y / Game1.tileSize))) return true;
|
||||
|
||||
//position does not take viewport into account since the entire map needs to be checked.
|
||||
Map map = Game1.currentLocation.map;
|
||||
if (position.X < 0 || position.X > map.Layers[0].DisplayWidth) return false;
|
||||
if (position.Y < 0 || position.Y > map.Layers[0].DisplayHeight) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
99
stardew-access/Features/Utils.cs
Normal file
99
stardew-access/Features/Utils.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
namespace stardew_access.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a custom enum class and contains the name of groups the objects are divided into for the feature
|
||||
/// </summary>
|
||||
public class CATEGORY
|
||||
{
|
||||
private string _typeKeyWord;
|
||||
|
||||
private CATEGORY(string typeKeyWord)
|
||||
{
|
||||
_typeKeyWord = typeKeyWord;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _typeKeyWord;
|
||||
}
|
||||
|
||||
public static CATEGORY FromString(string name)
|
||||
{
|
||||
if (name == "farmer")
|
||||
return CATEGORY.Farmers;
|
||||
else if (name == "animal")
|
||||
return CATEGORY.FarmAnimals;
|
||||
else if (name == "npc")
|
||||
return CATEGORY.NPCs;
|
||||
else if (name == "furniture")
|
||||
return CATEGORY.Furnitures;
|
||||
else if (name == "flooring")
|
||||
return CATEGORY.Flooring;
|
||||
else if (name == "debris")
|
||||
return CATEGORY.Debris;
|
||||
else if (name == "crop")
|
||||
return CATEGORY.Crops;
|
||||
else if (name == "tree")
|
||||
return CATEGORY.Trees;
|
||||
else if (name == "bush")
|
||||
return CATEGORY.Bush;
|
||||
else if (name == "building")
|
||||
return CATEGORY.Buildings;
|
||||
else if (name == "mine item")
|
||||
return CATEGORY.MineItems;
|
||||
else if (name == "resource clump")
|
||||
return CATEGORY.ResourceClumps;
|
||||
else if (name == "container")
|
||||
return CATEGORY.Containers;
|
||||
else if (name == "bundle")
|
||||
return CATEGORY.JunimoBundle;
|
||||
else if (name == "door")
|
||||
return CATEGORY.Doors;
|
||||
else if (name == "water")
|
||||
return CATEGORY.WaterTiles;
|
||||
else if (name == "interactable")
|
||||
return CATEGORY.Interactables;
|
||||
else if (name == "decoration")
|
||||
return CATEGORY.Decor;
|
||||
else if (name == "machine")
|
||||
return CATEGORY.Machines;
|
||||
else if (name == "bridge")
|
||||
return CATEGORY.Bridges;
|
||||
else if (name == "dropped item")
|
||||
return CATEGORY.DroppedItems;
|
||||
else if (name == "other")
|
||||
return CATEGORY.Others;
|
||||
|
||||
return Others;
|
||||
}
|
||||
|
||||
public static CATEGORY Farmers = new CATEGORY("farmer");
|
||||
public static CATEGORY FarmAnimals = new CATEGORY("animal");
|
||||
public static CATEGORY NPCs = new CATEGORY("npc");
|
||||
public static CATEGORY Furnitures = new CATEGORY("furniture");
|
||||
public static CATEGORY Flooring = new CATEGORY("flooring");
|
||||
public static CATEGORY Debris = new CATEGORY("debris");
|
||||
public static CATEGORY Crops = new CATEGORY("crop");
|
||||
public static CATEGORY Trees = new CATEGORY("tree");
|
||||
public static CATEGORY Bush = new CATEGORY("bush");
|
||||
public static CATEGORY Buildings = new CATEGORY("building");
|
||||
public static CATEGORY MineItems = new CATEGORY("mine item");
|
||||
public static CATEGORY ResourceClumps = new CATEGORY("resource clump");
|
||||
public static CATEGORY Containers = new CATEGORY("container");
|
||||
public static CATEGORY JunimoBundle = new CATEGORY("bundle");
|
||||
public static CATEGORY Doors = new CATEGORY("door"); // Also includes ladders and elevators
|
||||
public static CATEGORY WaterTiles = new CATEGORY("water");
|
||||
public static CATEGORY Interactables = new CATEGORY("interactable");
|
||||
public static CATEGORY Decor = new CATEGORY("decoration");
|
||||
public static CATEGORY Machines = new CATEGORY("machine");
|
||||
public static CATEGORY Bridges = new CATEGORY("bridge");
|
||||
public static CATEGORY DroppedItems = new CATEGORY("dropped item");
|
||||
public static CATEGORY Others = new CATEGORY("other");
|
||||
|
||||
}
|
||||
|
||||
public enum MachineState
|
||||
{
|
||||
Ready, Busy, Waiting
|
||||
}
|
||||
}
|
90
stardew-access/Features/Warnings.cs
Normal file
90
stardew-access/Features/Warnings.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
namespace stardew_access.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// Warns the player when their health or stamina/energy is low. Also warns when its past midnight.
|
||||
/// </summary>
|
||||
public class Warnings
|
||||
{
|
||||
// Store the previously checked value
|
||||
private int prevStamina;
|
||||
private int prevHealth;
|
||||
private int prevHour;
|
||||
|
||||
public Warnings()
|
||||
{
|
||||
prevStamina = 100;
|
||||
prevHealth = 100;
|
||||
prevHour = 6;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
this.checkForHealth();
|
||||
this.checkForStamina();
|
||||
this.checkForTimeOfDay();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warns when its past 12:00 am and 1:00 am
|
||||
/// </summary>
|
||||
private void checkForTimeOfDay()
|
||||
{
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
int hours = StardewValley.Game1.timeOfDay / 100;
|
||||
string toSpeak = MainClass.ModHelper.Translation.Get("warnings.time", new { value = CurrentPlayer.TimeOfDay });
|
||||
|
||||
if (hours < 1 && prevHour > 2 || hours >= 1 && prevHour < 1)
|
||||
{
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
// Pause the read tile feature to prevent interruption in warning message
|
||||
MainClass.ReadTileFeature.pauseUntil();
|
||||
}
|
||||
|
||||
prevHour = hours;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warns when stamina reaches below 50, 25 and 10.
|
||||
/// </summary>
|
||||
public void checkForStamina()
|
||||
{
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
int stamina = CurrentPlayer.PercentStamina;
|
||||
string toSpeak = MainClass.ModHelper.Translation.Get("warnings.stamina", new { value = stamina });
|
||||
|
||||
if ((stamina <= 50 && prevStamina > 50) || (stamina <= 25 && prevStamina > 25) || (stamina <= 10 && prevStamina > 10))
|
||||
{
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
// Pause the read tile feature to prevent interruption in warning message
|
||||
MainClass.ReadTileFeature.pauseUntil();
|
||||
}
|
||||
|
||||
prevStamina = stamina;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warns when health reaches below 50, 25 and 10.
|
||||
/// </summary>
|
||||
public void checkForHealth()
|
||||
{
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
int health = CurrentPlayer.PercentHealth;
|
||||
string toSpeak = MainClass.ModHelper.Translation.Get("warnings.health", new { value = health });
|
||||
|
||||
if ((health <= 50 && prevHealth > 50) || (health <= 25 && prevHealth > 25) || (health <= 10 && prevHealth > 10))
|
||||
{
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
// Pause the read tile feature to prevent interruption in warning message
|
||||
MainClass.ReadTileFeature.pauseUntil();
|
||||
}
|
||||
|
||||
prevHealth = health;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,11 @@
|
||||
using HarmonyLib;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using stardew_access.Patches;
|
||||
using StardewValley;
|
||||
using StardewValley.Menus;
|
||||
using StardewValley.Minigames;
|
||||
|
||||
namespace stardew_access
|
||||
{
|
||||
@@ -26,6 +28,11 @@ namespace stardew_access
|
||||
original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawHoverText), new Type[] { typeof(SpriteBatch), typeof(string), typeof(SpriteFont), typeof(int), typeof(int), typeof(int), typeof(string), typeof(int), typeof(string[]), typeof(Item), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(float), typeof(CraftingRecipe), typeof(IList<Item>) }),
|
||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.HoverTextPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(NPC), nameof(NPC.drawAboveAlwaysFrontLayer)),
|
||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.drawAboveAlwaysFrontLayerPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Title Menu Patches
|
||||
@@ -41,13 +48,18 @@ namespace stardew_access
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(CharacterCustomization), nameof(CharacterCustomization.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.NewGameMenuPatch))
|
||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.CharacterCustomizationMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(CoopMenu), nameof(CoopMenu.update), new Type[] { typeof(GameTime) }),
|
||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.CoopMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(AdvancedGameOptions), nameof(AdvancedGameOptions.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.AdvancedGameOptionsPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Game Menu Patches
|
||||
@@ -96,16 +108,28 @@ namespace stardew_access
|
||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.SocialPagePatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(CollectionsPage), nameof(CollectionsPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.CollectionsPagePatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Bundle Menu Patches
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(JunimoNoteMenu), nameof(JunimoNoteMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.JunimoNoteMenuPatch))
|
||||
postfix: new HarmonyMethod(typeof(BundleMenuPatches), nameof(BundleMenuPatches.JunimoNoteMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(JojaCDMenu), nameof(JojaCDMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(BundleMenuPatches), nameof(BundleMenuPatches.JojaCDMenuPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Menu Patches
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(LetterViewerMenu), nameof(LetterViewerMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.LetterViewerMenuPatch))
|
||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.LetterViewerMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
@@ -124,7 +148,12 @@ namespace stardew_access
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Constructor(typeof(NamingMenu), new Type[] { typeof(NamingMenu.doneNamingBehavior), typeof(string), typeof(string) }),
|
||||
original: AccessTools.Method(typeof(TitleTextInputMenu), nameof(TitleTextInputMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.TitleTextInputMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(NamingMenu), nameof(NamingMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.NamingMenuPatch))
|
||||
);
|
||||
|
||||
@@ -137,6 +166,36 @@ namespace stardew_access
|
||||
original: AccessTools.Method(typeof(LanguageSelectionMenu), nameof(LanguageSelectionMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.LanguageSelectionMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(MuseumMenu), nameof(MuseumMenu.receiveKeyPress), new Type[] { typeof(Keys) }),
|
||||
prefix: new HarmonyMethod(typeof(DonationMenuPatches), nameof(DonationMenuPatches.MuseumMenuKeyPressPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(ChooseFromListMenu), nameof(ChooseFromListMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ChooseFromListMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(TailoringMenu), nameof(TailoringMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.TailoringMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(PondQueryMenu), nameof(PondQueryMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.PondQueryMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(ForgeMenu), nameof(ForgeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ForgeMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(ItemListMenu), nameof(ItemListMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ItemListMenuPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Quest Patches
|
||||
@@ -159,7 +218,7 @@ namespace stardew_access
|
||||
#region Chat Menu Patches
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(ChatBox), nameof(ChatBox.update), new Type[] { typeof(GameTime) }),
|
||||
postfix: new HarmonyMethod(typeof(ChatManuPatches), nameof(ChatManuPatches.ChatBoxPatch))
|
||||
postfix: new HarmonyMethod(typeof(ChatMenuPatches), nameof(ChatMenuPatches.ChatBoxPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
@@ -186,6 +245,35 @@ namespace stardew_access
|
||||
prefix: new HarmonyMethod(typeof(BuildingNAnimalMenuPatches), nameof(BuildingNAnimalMenuPatches.PurchaseAnimalsMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(AnimalQueryMenu), nameof(AnimalQueryMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(BuildingNAnimalMenuPatches), nameof(BuildingNAnimalMenuPatches.AnimalQueryMenuPatch))
|
||||
);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Donation Menus
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(MuseumMenu), nameof(MuseumMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(DonationMenuPatches), nameof(DonationMenuPatches.MuseumMenuPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(FieldOfficeMenu), nameof(FieldOfficeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(DonationMenuPatches), nameof(DonationMenuPatches.FieldOfficeMenuPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region Mini Games
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(Intro), nameof(Intro.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MiniGamesPatches), nameof(MiniGamesPatches.IntroPatch))
|
||||
);
|
||||
|
||||
harmony.Patch(
|
||||
original: AccessTools.Method(typeof(GrandpaStory), nameof(GrandpaStory.draw), new Type[] { typeof(SpriteBatch) }),
|
||||
postfix: new HarmonyMethod(typeof(MiniGamesPatches), nameof(MiniGamesPatches.GrandpaStoryPatch))
|
||||
);
|
||||
#endregion
|
||||
|
||||
harmony.Patch(
|
||||
|
88
stardew-access/ModConfig.cs
Normal file
88
stardew-access/ModConfig.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using StardewModdingAPI.Utilities;
|
||||
|
||||
namespace stardew_access
|
||||
{
|
||||
internal class ModConfig
|
||||
{
|
||||
// https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Input#SButton button key codes
|
||||
|
||||
#region Simulate mouse clicks
|
||||
public KeybindList LeftClickMainKey { get; set; } = KeybindList.Parse("LeftControl + Enter"); // Primary key to simulate mouse left click
|
||||
public KeybindList RightClickMainKey { get; set; } = KeybindList.Parse("LeftShift + Enter"); // Primary key to simulate mouse right click
|
||||
public KeybindList LeftClickAlternateKey { get; set; } = KeybindList.Parse("OemOpenBrackets"); // Secondary key to simulate mouse left click
|
||||
public KeybindList RightClickAlternateKey { get; set; } = KeybindList.Parse("OemCloseBrackets"); // Secondary key to simulate mouse right click
|
||||
#endregion
|
||||
|
||||
#region Chat menu
|
||||
public KeybindList ChatMenuNextKey { get; set; } = KeybindList.Parse("PageUp"); // Read previous chat message
|
||||
public KeybindList ChatMenuPreviousKey { get; set; } = KeybindList.Parse("PageDown"); // Read next chat message
|
||||
#endregion
|
||||
|
||||
#region Read tile
|
||||
public Boolean ReadTile { get; set; } = true; // Toggle this feature.
|
||||
public KeybindList ReadTileKey { get; set; } = KeybindList.Parse("J"); // Manually trigger read tile for the tile player is *looking at*.
|
||||
public KeybindList ReadStandingTileKey { get; set; } = KeybindList.Parse("LeftAlt + J"); // Manually trigger read tile for the tile player is *standing on*.
|
||||
public Boolean ReadFlooring { get; set; } = false; // Toggle reading floorings.
|
||||
public Boolean WateredToggle { get; set; } = true; // Toggle speaking watered or unwatered for crops.
|
||||
#endregion
|
||||
|
||||
#region Tile viewer
|
||||
public KeybindList TileCursorUpKey { get; set; } = KeybindList.Parse("Up"); // Move the cursor one tile up
|
||||
public KeybindList TileCursorRightKey { get; set; } = KeybindList.Parse("Right"); // Move the cursor one tile right
|
||||
public KeybindList TileCursorDownKey { get; set; } = KeybindList.Parse("Down"); // Move the cursor one tile down
|
||||
public KeybindList TileCursorLeftKey { get; set; } = KeybindList.Parse("Left"); // Move the cursor one tile left
|
||||
public KeybindList TileCursorPreciseUpKey { get; set; } = KeybindList.Parse("LeftShift + Up"); // Move the cursor up by precision i.e. pixel by pixel
|
||||
public KeybindList TileCursorPreciseRightKey { get; set; } = KeybindList.Parse("LeftShift + Right"); // Move the cursor right by precision i.e. pixel by pixel
|
||||
public KeybindList TileCursorPreciseDownKey { get; set; } = KeybindList.Parse("LeftShift + Down"); // Move the cursor down by precision i.e. pixel by pixel
|
||||
public KeybindList TileCursorPreciseLeftKey { get; set; } = KeybindList.Parse("LeftShift + Left"); // Move the cursor left by precision i.e. pixel by pixel
|
||||
public KeybindList ToggleRelativeCursorLockKey { get; set; } = KeybindList.Parse("L"); // Toggles realative cursor lock i.e. if enabled, the cursor will reset when player moves.
|
||||
public KeybindList AutoWalkToTileKey { get; set; } = KeybindList.Parse("LeftControl + Enter"); // Auto walk to the tile
|
||||
public bool LimitTileCursorToScreen { get; set; } = false; // #TODO add command for this // Toggle whether to prevent cursor from going out of screen.
|
||||
public int TileCursorPreciseMovementDistance { get; set; } = 8; // Specifies the number of pixels the cursor should move when using precision movement i.e. with *left shift*.
|
||||
#endregion
|
||||
|
||||
#region Radar
|
||||
public Boolean Radar { get; set; } = false;
|
||||
public Boolean RadarStereoSound { get; set; } = true;
|
||||
#endregion
|
||||
|
||||
#region Menu Keys
|
||||
public KeybindList PrimaryInfoKey { get; set; } = KeybindList.Parse("C");
|
||||
|
||||
// Charachter Creatinon menu (new game menu) keys
|
||||
public KeybindList CharacterCreationMenuNextKey { get; set; } = KeybindList.Parse("Right");
|
||||
public KeybindList CharacterCreationMenuPreviousKey { get; set; } = KeybindList.Parse("Left");
|
||||
|
||||
// Bundle menu keys
|
||||
public KeybindList BundleMenuIngredientsKey { get; set; } = KeybindList.Parse("I");
|
||||
public KeybindList BundleMenuInventoryItemsKey { get; set; } = KeybindList.Parse("C");
|
||||
public KeybindList BundleMenuPurchaseButtonKey { get; set; } = KeybindList.Parse("P");
|
||||
public KeybindList BundleMenuIngredientsInputSlotKey { get; set; } = KeybindList.Parse("V");
|
||||
public KeybindList BundleMenuBackButtonKey { get; set; } = KeybindList.Parse("Back");
|
||||
|
||||
// Menus with secondary inventory(shop inventory or chest inventory or crafting recipe list)
|
||||
public KeybindList SnapToFirstInventorySlotKey { get; set; } = KeybindList.Parse("I");
|
||||
public KeybindList SnapToFirstSecondaryInventorySlotKey { get; set; } = KeybindList.Parse("LeftShift + I");
|
||||
|
||||
// Crafting menu
|
||||
public KeybindList CraftingMenuCycleThroughRecipiesKey { get; set; } = KeybindList.Parse("C");
|
||||
#endregion
|
||||
|
||||
#region Others
|
||||
public KeybindList HealthNStaminaKey { get; set; } = KeybindList.Parse("H"); // Narrate health and stamina.
|
||||
public bool HealthNStaminaInPercentage { get; set; } = true;
|
||||
public KeybindList PositionKey { get; set; } = KeybindList.Parse("K"); // Narrate player position.
|
||||
public KeybindList LocationKey { get; set; } = KeybindList.Parse("LeftAlt + K"); // Narrate current location name.
|
||||
public KeybindList MoneyKey { get; set; } = KeybindList.Parse("R"); // Narrate the money the player has currently.
|
||||
public KeybindList TimeNSeasonKey { get; set; } = KeybindList.Parse("Q"); // Narrate the time of day, day and date and season
|
||||
public Boolean VerboseCoordinates { get; set; } = true;
|
||||
public Boolean SnapMouse { get; set; } = true; // Toggles the snap mouse feature
|
||||
public Boolean Warning { get; set; } = true; // Toggles the warnings feature
|
||||
public Boolean TTS { get; set; } = true; // Toggles the screen reader/tts.
|
||||
public Boolean TrackDroppedItems {get; set;} = true; // Toggles detecting the dropped items.
|
||||
#endregion
|
||||
|
||||
// TODO Add the exclusion and focus list too
|
||||
// public String ExclusionList { get; set; } = "test";
|
||||
}
|
||||
}
|
@@ -6,49 +6,102 @@ using HarmonyLib;
|
||||
using stardew_access.Patches;
|
||||
using stardew_access.ScreenReader;
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewValley.Menus;
|
||||
|
||||
namespace stardew_access
|
||||
{
|
||||
public class MainClass : Mod
|
||||
{
|
||||
#region Global Vars & Properties
|
||||
#pragma warning disable CS8603
|
||||
private static int prevDate = -99;
|
||||
private static ModConfig? config;
|
||||
private Harmony? harmony;
|
||||
public static bool readTile = true;
|
||||
public static bool snapMouse = true;
|
||||
public static bool isNarratingHudMessage = false;
|
||||
public static bool radar = false;
|
||||
public static bool radarDebug = false;
|
||||
public static bool radarStereoSound = true;
|
||||
private static IMonitor monitor;
|
||||
public static string hudMessageQueryKey = "";
|
||||
private static Radar radarFeature;
|
||||
private static IMonitor? monitor;
|
||||
private static Radar? radarFeature;
|
||||
private static StaticTiles? sTiles;
|
||||
private static IScreenReader? screenReader;
|
||||
private static IModHelper modHelper;
|
||||
private static IModHelper? modHelper;
|
||||
private static TileViewer? tileViewer;
|
||||
private static Warnings? warnings;
|
||||
private static ReadTile? readTile;
|
||||
|
||||
public static IModHelper ModHelper { get => modHelper; }
|
||||
public static Radar RadarFeature { get => radarFeature; set => radarFeature = value; }
|
||||
internal static ModConfig Config { get => config; set => config = value; }
|
||||
public static IModHelper? ModHelper { get => modHelper; }
|
||||
|
||||
public static IScreenReader GetScreenReader()
|
||||
public static StaticTiles STiles
|
||||
{
|
||||
if (screenReader == null)
|
||||
screenReader = new ScreenReaderController().Initialize();
|
||||
return screenReader;
|
||||
get
|
||||
{
|
||||
if (sTiles == null)
|
||||
sTiles = new StaticTiles();
|
||||
|
||||
return sTiles;
|
||||
}
|
||||
set => sTiles = value;
|
||||
}
|
||||
public static Radar RadarFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
if (radarFeature == null)
|
||||
radarFeature = new Radar();
|
||||
|
||||
return radarFeature;
|
||||
}
|
||||
set => radarFeature = value;
|
||||
}
|
||||
|
||||
public static void SetScreenReader(IScreenReader value)
|
||||
public static string hudMessageQueryKey = "";
|
||||
public static bool isNarratingHudMessage = false;
|
||||
public static bool radarDebug = false;
|
||||
|
||||
public static IScreenReader ScreenReader
|
||||
{
|
||||
screenReader = value;
|
||||
get
|
||||
{
|
||||
if (screenReader == null)
|
||||
screenReader = new ScreenReaderController().Initialize();
|
||||
|
||||
return screenReader;
|
||||
}
|
||||
|
||||
set => screenReader = value;
|
||||
}
|
||||
|
||||
public static IMonitor GetMonitor()
|
||||
public static TileViewer TileViewerFeature
|
||||
{
|
||||
return monitor;
|
||||
get
|
||||
{
|
||||
if (tileViewer == null)
|
||||
tileViewer = new TileViewer();
|
||||
return tileViewer;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetMonitor(IMonitor value)
|
||||
public static ReadTile ReadTileFeature
|
||||
{
|
||||
monitor = value;
|
||||
get
|
||||
{
|
||||
if (readTile == null)
|
||||
readTile = new ReadTile();
|
||||
return readTile;
|
||||
}
|
||||
}
|
||||
|
||||
public static Warnings WarningsFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
if (warnings == null)
|
||||
warnings = new Warnings();
|
||||
|
||||
return warnings;
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS8603
|
||||
#endregion
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
@@ -57,20 +110,20 @@ namespace stardew_access
|
||||
public override void Entry(IModHelper helper)
|
||||
{
|
||||
#region Initializations
|
||||
Config = helper.ReadConfig<ModConfig>();
|
||||
|
||||
SetMonitor(base.Monitor); // Inititalize monitor
|
||||
monitor = base.Monitor; // Inititalize monitor
|
||||
modHelper = helper;
|
||||
|
||||
Game1.options.setGamepadMode("force_on");
|
||||
|
||||
SetScreenReader(new ScreenReaderController().Initialize());
|
||||
ScreenReader = new ScreenReaderController().Initialize();
|
||||
ScreenReader.Say("Initializing Stardew Access", true);
|
||||
|
||||
CustomSoundEffects.Initialize();
|
||||
|
||||
CustomCommands.Initialize();
|
||||
|
||||
RadarFeature = new Radar();
|
||||
|
||||
harmony = new Harmony(ModManifest.UniqueID);
|
||||
HarmonyPatches.Initialize(harmony);
|
||||
|
||||
@@ -94,9 +147,10 @@ namespace stardew_access
|
||||
|
||||
public void OnExit(object? sender, EventArgs? e)
|
||||
{
|
||||
// Don't if this ever gets called or not but, just in case if it does.
|
||||
if (GetScreenReader() != null)
|
||||
GetScreenReader().CloseScreenReader();
|
||||
// This closes the connection with the screen reader, important for linux
|
||||
// Don't know if this ever gets called or not but, just in case if it does.
|
||||
if (ScreenReader != null)
|
||||
ScreenReader.CloseScreenReader();
|
||||
}
|
||||
|
||||
/// <summary>Returns the Screen Reader class for other mods to use.</summary>
|
||||
@@ -110,26 +164,43 @@ namespace stardew_access
|
||||
if (!Context.IsPlayerFree)
|
||||
return;
|
||||
|
||||
// Reset variables
|
||||
MenuPatches.resetGlobalVars();
|
||||
QuestPatches.resetGlobalVars();
|
||||
|
||||
// Narrates currently selected inventory slot
|
||||
Other.narrateCurrentSlot();
|
||||
|
||||
// Narrate current location's name
|
||||
Other.narrateCurrentLocation();
|
||||
|
||||
if (snapMouse)
|
||||
Other.SnapMouseToPlayer();
|
||||
//handle TileCursor update logic
|
||||
TileViewerFeature.update();
|
||||
|
||||
if (!ReadTile.isReadingTile && readTile)
|
||||
ReadTile.run();
|
||||
if (Config.Warning)
|
||||
WarningsFeature.update();
|
||||
|
||||
if (!RadarFeature.isRunning && radar)
|
||||
if (Config.ReadTile)
|
||||
ReadTileFeature.update();
|
||||
|
||||
if (!RadarFeature.isRunning && Config.Radar)
|
||||
{
|
||||
RadarFeature.isRunning = true;
|
||||
RadarFeature.Run();
|
||||
Task.Delay(RadarFeature.delay).ContinueWith(_ => { RadarFeature.isRunning = false; });
|
||||
}
|
||||
|
||||
if (!isNarratingHudMessage)
|
||||
{
|
||||
isNarratingHudMessage = true;
|
||||
Other.narrateHudMessages();
|
||||
Task.Delay(300).ContinueWith(_ => { isNarratingHudMessage = false; });
|
||||
}
|
||||
|
||||
if (Game1.player != null)
|
||||
{
|
||||
if (Game1.timeOfDay >= 600 && prevDate != CurrentPlayer.Date)
|
||||
{
|
||||
prevDate = CurrentPlayer.Date;
|
||||
DebugLog("Refreshing buildlist...");
|
||||
CustomCommands.onBuildListCalled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,74 +209,172 @@ namespace stardew_access
|
||||
if (e == null)
|
||||
return;
|
||||
|
||||
#region Simulate left and right clicks
|
||||
if (Game1.activeClickableMenu != null)
|
||||
{
|
||||
bool isLeftShiftPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift);
|
||||
bool isLeftControlPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl);
|
||||
bool isCustomizingChrachter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
|
||||
|
||||
// Perform Left Click
|
||||
if (Equals(e.Button, SButton.OemOpenBrackets))
|
||||
#region Mouse Click Simulation
|
||||
// Main Keybinds
|
||||
if (Config.LeftClickMainKey.JustPressed())
|
||||
{
|
||||
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
if (isLeftControlPressed && Equals(e.Button, SButton.Enter))
|
||||
if (Config.RightClickMainKey.JustPressed())
|
||||
{
|
||||
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
|
||||
// Alternate Keybinds
|
||||
if (!isCustomizingChrachter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.LeftClickAlternateKey.JustPressed()) // Excluding the character creation menu
|
||||
{
|
||||
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
|
||||
// Perform Right CLick
|
||||
if (Equals(e.Button, SButton.OemCloseBrackets))
|
||||
{
|
||||
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
if (isLeftShiftPressed && Equals(e.Button, SButton.Enter))
|
||||
if (!isCustomizingChrachter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.RightClickAlternateKey.JustPressed()) // Excluding the character creation menu
|
||||
{
|
||||
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
if (Game1.currentMinigame != null)
|
||||
{
|
||||
bool isCustomizingChrachter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
|
||||
|
||||
#region Mouse Click Simulation
|
||||
// Main Keybinds
|
||||
if (Config.LeftClickMainKey.JustPressed())
|
||||
{
|
||||
Game1.currentMinigame.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
if (Config.RightClickMainKey.JustPressed())
|
||||
{
|
||||
Game1.currentMinigame.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
|
||||
// Alternate Keybinds
|
||||
if (Config.LeftClickAlternateKey.JustPressed())
|
||||
{
|
||||
Game1.currentMinigame.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
if (Config.RightClickAlternateKey.JustPressed())
|
||||
{
|
||||
Game1.currentMinigame.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (!Context.IsPlayerFree)
|
||||
return;
|
||||
|
||||
// Narrate health and stamina
|
||||
if (Equals(e.Button, SButton.H))
|
||||
// Stops the auto walk controller if any movement key(WASD) is pressed
|
||||
if (TileViewerFeature.isAutoWalking &&
|
||||
(e.Button.Equals(SButtonExtensions.ToSButton(Game1.options.moveUpButton[0]))
|
||||
|| e.Button.Equals(SButtonExtensions.ToSButton(Game1.options.moveDownButton[0]))
|
||||
|| e.Button.Equals(SButtonExtensions.ToSButton(Game1.options.moveLeftButton[0]))
|
||||
|| e.Button.Equals(SButtonExtensions.ToSButton(Game1.options.moveRightButton[0]))))
|
||||
{
|
||||
string toSpeak = $"Health is {CurrentPlayer.getHealth()} and Stamina is {CurrentPlayer.getStamina()}";
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
TileViewerFeature.stopAutoWalking(wasForced: true);
|
||||
}
|
||||
|
||||
// Narrate Current Location
|
||||
if (Config.LocationKey.JustPressed())
|
||||
{
|
||||
string toSpeak = $"{Game1.currentLocation.Name}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Narrate Position
|
||||
if (Equals(e.Button, SButton.K))
|
||||
if (Config.PositionKey.JustPressed())
|
||||
{
|
||||
string toSpeak = $"X: {CurrentPlayer.getPositionX()} , Y: {CurrentPlayer.getPositionY()}";
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
string toSpeak;
|
||||
if (Config.VerboseCoordinates)
|
||||
{
|
||||
toSpeak = $"X: {CurrentPlayer.PositionX}, Y: {CurrentPlayer.PositionY}";
|
||||
}
|
||||
else
|
||||
{
|
||||
toSpeak = $"{CurrentPlayer.PositionX}, {CurrentPlayer.PositionY}";
|
||||
}
|
||||
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Narrate health and stamina
|
||||
if (Config.HealthNStaminaKey.JustPressed())
|
||||
{
|
||||
if (ModHelper == null)
|
||||
return;
|
||||
|
||||
string toSpeak;
|
||||
if (Config.HealthNStaminaInPercentage)
|
||||
toSpeak = ModHelper.Translation.Get("manuallytriggered.healthnstamina.percent", new { health = CurrentPlayer.PercentHealth, stamina = CurrentPlayer.PercentStamina });
|
||||
else
|
||||
toSpeak = ModHelper.Translation.Get("manuallytriggered.healthnstamina.normal", new { health = CurrentPlayer.CurrentHealth, stamina = CurrentPlayer.CurrentStamina });
|
||||
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Narrate money at hand
|
||||
if (Equals(e.Button, SButton.R))
|
||||
if (Config.MoneyKey.JustPressed())
|
||||
{
|
||||
string toSpeak = $"You have {CurrentPlayer.getMoney()}g";
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
string toSpeak = $"You have {CurrentPlayer.Money}g";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Narrate time and season
|
||||
if (Equals(e.Button, SButton.Q))
|
||||
if (Config.TimeNSeasonKey.JustPressed())
|
||||
{
|
||||
string toSpeak = $"Time is {CurrentPlayer.getTimeOfDay()} and it is {CurrentPlayer.getDay()} {CurrentPlayer.getDate()} of {CurrentPlayer.getSeason()}";
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
string toSpeak = $"Time is {CurrentPlayer.TimeOfDay} and it is {CurrentPlayer.Day} {CurrentPlayer.Date} of {CurrentPlayer.Season}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Manual read tile
|
||||
if (Equals(e.Button, SButton.J))
|
||||
// Manual read tile at player's position
|
||||
if (Config.ReadStandingTileKey.JustPressed())
|
||||
{
|
||||
ReadTile.run(manuallyTriggered: true);
|
||||
ReadTileFeature.run(manuallyTriggered: true, playersPosition: true);
|
||||
return;
|
||||
}
|
||||
|
||||
/*if (Equals(e.Button, SButton.B))
|
||||
// Manual read tile at looking tile
|
||||
if (Config.ReadTileKey.JustPressed())
|
||||
{
|
||||
Game1.player.controller = new PathFindController(Game1.player, Game1.currentLocation, new Point(49,13), 2);
|
||||
monitor.Log($"{Game1.player.controller.pathToEndPoint==null}", LogLevel.Debug); // true if path not found
|
||||
}*/
|
||||
ReadTileFeature.run(manuallyTriggered: true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Tile viewing cursor keys
|
||||
TileViewerFeature.HandleInput();
|
||||
}
|
||||
|
||||
public static void ErrorLog(string message)
|
||||
{
|
||||
if (monitor == null)
|
||||
return;
|
||||
|
||||
monitor.Log(message, LogLevel.Error);
|
||||
}
|
||||
|
||||
public static void InfoLog(string message)
|
||||
{
|
||||
if (monitor == null)
|
||||
return;
|
||||
|
||||
monitor.Log(message, LogLevel.Info);
|
||||
}
|
||||
|
||||
public static void DebugLog(string message)
|
||||
{
|
||||
if (monitor == null)
|
||||
return;
|
||||
|
||||
monitor.Log(message, LogLevel.Debug);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley.Buildings;
|
||||
using StardewValley.Locations;
|
||||
@@ -13,20 +12,100 @@ namespace stardew_access.Patches
|
||||
internal static Vector2[] marked = new Vector2[10];
|
||||
internal static Building?[] availableBuildings = new Building[100];
|
||||
internal static CarpenterMenu? carpenterMenu = null;
|
||||
internal static bool isNarratingAnimalInfo = false;
|
||||
internal static string animalQueryMenuQuery = " ";
|
||||
internal static string carpenterMenuQuery = "", purchaseAnimalMenuQuery = "";
|
||||
internal static bool isSayingBlueprintInfo = false;
|
||||
internal static string prevBlueprintInfo = "";
|
||||
internal static bool isOnFarm = false, isUpgrading = false, isDemolishing = false, isPainting = false, isConstructing = false, isMoving = false, isMagicalConstruction = false;
|
||||
internal static bool firstTimeInNamingMenu = true;
|
||||
internal static PurchaseAnimalsMenu? purchaseAnimalsMenu;
|
||||
internal static AnimalQueryMenu? animalQueryMenu;
|
||||
private static FarmAnimal? animalBeingPurchasedOrMoved = null;
|
||||
|
||||
internal static void PurchaseAnimalsMenuPatch(PurchaseAnimalsMenu __instance, bool ___onFarm, bool ___namingAnimal, TextBox ___textBox)
|
||||
internal static void AnimalQueryMenuPatch(AnimalQueryMenu __instance, bool ___confirmingSell, FarmAnimal ___animal, TextBox ___textBox, string ___parentName, bool ___movingAnimal)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY(); // Mouse x and y position
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); // For narrating animal details
|
||||
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
||||
string toSpeak = " ", details = " ";
|
||||
|
||||
isOnFarm = ___movingAnimal;
|
||||
animalQueryMenu = __instance;
|
||||
animalBeingPurchasedOrMoved = ___animal;
|
||||
|
||||
if (___textBox.Selected)
|
||||
{
|
||||
toSpeak = ___textBox.Text;
|
||||
|
||||
if (isEscPressed)
|
||||
{
|
||||
___textBox.Selected = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isPrimaryInfoKeyPressed & !isNarratingAnimalInfo)
|
||||
{
|
||||
string name = ___animal.displayName;
|
||||
string type = ___animal.displayType;
|
||||
int age = (___animal.GetDaysOwned() + 1) / 28 + 1;
|
||||
string ageText = (age <= 1) ? Game1.content.LoadString("Strings\\UI:AnimalQuery_Age1") : Game1.content.LoadString("Strings\\UI:AnimalQuery_AgeN", age);
|
||||
string parent = "";
|
||||
if ((int)___animal.age.Value < (byte)___animal.ageWhenMature.Value)
|
||||
{
|
||||
ageText += Game1.content.LoadString("Strings\\UI:AnimalQuery_AgeBaby");
|
||||
}
|
||||
if (___parentName != null)
|
||||
{
|
||||
parent = Game1.content.LoadString("Strings\\UI:AnimalQuery_Parent", ___parentName);
|
||||
}
|
||||
|
||||
details = $"Name: {name} Type: {type} \n\t Age: {ageText} {parent}";
|
||||
animalQueryMenuQuery = " ";
|
||||
|
||||
isNarratingAnimalInfo = true;
|
||||
Task.Delay(200).ContinueWith(_ => { isNarratingAnimalInfo = false; });
|
||||
}
|
||||
|
||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
toSpeak = "OK button";
|
||||
else if (__instance.sellButton != null && __instance.sellButton.containsPoint(x, y))
|
||||
toSpeak = $"Sell for {___animal.getSellPrice()}g button";
|
||||
else if (___confirmingSell && __instance.yesButton != null && __instance.yesButton.containsPoint(x, y))
|
||||
toSpeak = "Confirm selling animal";
|
||||
else if (___confirmingSell && __instance.noButton != null && __instance.noButton.containsPoint(x, y))
|
||||
toSpeak = "Cancel selling animal";
|
||||
else if (__instance.moveHomeButton != null && __instance.moveHomeButton.containsPoint(x, y))
|
||||
toSpeak = "Change home building button";
|
||||
else if (__instance.allowReproductionButton != null && __instance.allowReproductionButton.containsPoint(x, y))
|
||||
toSpeak = ((___animal.allowReproduction.Value) ? "Enabled" : "Disabled") + " allow reproduction button";
|
||||
else if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
||||
toSpeak = "Animal name text box";
|
||||
}
|
||||
|
||||
if (animalQueryMenuQuery != toSpeak)
|
||||
{
|
||||
animalQueryMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say($"{details} {toSpeak}", true);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void PurchaseAnimalsMenuPatch(PurchaseAnimalsMenu __instance, bool ___onFarm, bool ___namingAnimal, TextBox ___textBox, FarmAnimal ___animalBeingPurchased)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
purchaseAnimalsMenu = __instance;
|
||||
isOnFarm = ___onFarm;
|
||||
animalBeingPurchasedOrMoved = ___animalBeingPurchased;
|
||||
|
||||
if (___onFarm && ___namingAnimal)
|
||||
{
|
||||
@@ -61,7 +140,7 @@ namespace stardew_access.Patches
|
||||
firstTimeInNamingMenu = false;
|
||||
}
|
||||
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
else if (___onFarm && !___namingAnimal)
|
||||
@@ -90,7 +169,7 @@ namespace stardew_access.Patches
|
||||
if (purchaseAnimalMenuQuery != toSpeak)
|
||||
{
|
||||
purchaseAnimalMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -98,7 +177,7 @@ namespace stardew_access.Patches
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +204,8 @@ namespace stardew_access.Patches
|
||||
if (currentBluprint == null)
|
||||
return;
|
||||
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY(); // Mouse x and y position
|
||||
bool isBPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.B);
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||
string ingredients = "";
|
||||
string name = currentBluprint.displayName;
|
||||
string upgradeName = currentBluprint.nameOfBuildingToUpgrade;
|
||||
@@ -143,7 +222,7 @@ namespace stardew_access.Patches
|
||||
int itemStack = ___ingredients[i].Stack;
|
||||
string itemQuality = "";
|
||||
|
||||
int qualityValue = ((StardewValley.Object)___ingredients[i]).quality;
|
||||
int qualityValue = ((StardewValley.Object)___ingredients[i]).Quality;
|
||||
if (qualityValue == 1)
|
||||
{
|
||||
itemQuality = "Silver quality";
|
||||
@@ -163,7 +242,7 @@ namespace stardew_access.Patches
|
||||
|
||||
blueprintInfo = $"{name}, Price: {price}, Ingredients: {ingredients}, Dimensions: {width} width and {height} height, Description: {description}";
|
||||
|
||||
if (isBPressed && !isSayingBlueprintInfo)
|
||||
if (isPrimaryInfoKeyPressed && !isSayingBlueprintInfo)
|
||||
{
|
||||
SayBlueprintInfo(blueprintInfo);
|
||||
}
|
||||
@@ -180,7 +259,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -191,7 +270,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -202,7 +281,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -213,7 +292,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -224,7 +303,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -235,7 +314,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -246,7 +325,7 @@ namespace stardew_access.Patches
|
||||
if (carpenterMenuQuery != toSpeak)
|
||||
{
|
||||
carpenterMenuQuery = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -269,14 +348,14 @@ namespace stardew_access.Patches
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async void SayBlueprintInfo(string info)
|
||||
{
|
||||
isSayingBlueprintInfo = true;
|
||||
MainClass.GetScreenReader().Say(info, true);
|
||||
MainClass.ScreenReader.Say(info, true);
|
||||
await Task.Delay(300);
|
||||
isSayingBlueprintInfo = false;
|
||||
}
|
||||
@@ -300,7 +379,7 @@ namespace stardew_access.Patches
|
||||
{
|
||||
if (isDemolishing && toDemolish != null && farm.buildings.Contains(toDemolish))
|
||||
{
|
||||
if ((int)toDemolish.daysOfConstructionLeft > 0 || (int)toDemolish.daysUntilUpgrade > 0)
|
||||
if ((int)toDemolish.daysOfConstructionLeft.Value > 0 || (int)toDemolish.daysUntilUpgrade.Value > 0)
|
||||
{
|
||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_DuringConstruction");
|
||||
}
|
||||
@@ -345,8 +424,8 @@ namespace stardew_access.Patches
|
||||
}
|
||||
if (farm.destroyStructure(toDemolish))
|
||||
{
|
||||
_ = (int)toDemolish.tileY;
|
||||
_ = (int)toDemolish.tilesHigh;
|
||||
_ = (int)toDemolish.tileY.Value;
|
||||
_ = (int)toDemolish.tilesHigh.Value;
|
||||
Game1.flashAlpha = 1f;
|
||||
toDemolish.showDestroyedAnimation(Game1.getFarm());
|
||||
Game1.playSound("explosion");
|
||||
@@ -356,7 +435,7 @@ namespace stardew_access.Patches
|
||||
// freeze = true;
|
||||
if (chest != null)
|
||||
{
|
||||
farm.objects[new Vector2((int)toDemolish.tileX + (int)toDemolish.tilesWide / 2, (int)toDemolish.tileY + (int)toDemolish.tilesHigh / 2)] = chest;
|
||||
farm.objects[new Vector2((int)toDemolish.tileX.Value + (int)toDemolish.tilesWide.Value / 2, (int)toDemolish.tileY.Value + (int)toDemolish.tilesHigh.Value / 2)] = chest;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,7 +464,7 @@ namespace stardew_access.Patches
|
||||
if (toDemolish != null && toDemolish.indoors.Value is Cabin)
|
||||
{
|
||||
Cabin cabin = (Cabin)toDemolish.indoors.Value;
|
||||
if (cabin.farmhand.Value != null && (bool)cabin.farmhand.Value.isCustomized)
|
||||
if (cabin.farmhand.Value != null && (bool)cabin.farmhand.Value.isCustomized.Value)
|
||||
{
|
||||
Game1.currentLocation.createQuestionDialogue(Game1.content.LoadString("Strings\\UI:Carpenter_DemolishCabinConfirm", cabin.farmhand.Value.Name), Game1.currentLocation.createYesNoResponses(), delegate (Farmer f, string answer)
|
||||
{
|
||||
@@ -458,7 +537,7 @@ namespace stardew_access.Patches
|
||||
Game1.playSound("axe");
|
||||
DelayedAction.functionAfterDelay(carpenterMenu.returnToCarpentryMenuAfterSuccessfulBuild, 1500);
|
||||
// freeze = true;
|
||||
// Game1.multiplayer.globalChatInfoMessage("BuildingBuild", Game1.player.Name, Utility.AOrAn(carpenterMenu.CurrentBlueprint.displayName), carpenterMenu.CurrentBlueprint.displayName, Game1.player.farmName);
|
||||
// Game1.multiplayer.globalChatInfoMessage("BuildingBuild", Game1.player.Name, Utility.AOrAn(carpenterMenu.CurrentBlueprint.displayName), carpenterMenu.CurrentBlueprint.displayName, Game1.player.farmName.Value);
|
||||
}
|
||||
else if (toUpgrade != null)
|
||||
{
|
||||
@@ -517,7 +596,7 @@ namespace stardew_access.Patches
|
||||
string? name = buildingToMove.nameOfIndoorsWithoutUnique;
|
||||
name = (name == "null") ? buildingToMove.buildingType.Value : name;
|
||||
|
||||
if ((int)buildingToMove.daysOfConstructionLeft > 0)
|
||||
if ((int)buildingToMove.daysOfConstructionLeft.Value > 0)
|
||||
{
|
||||
buildingToMove = null;
|
||||
return "Building under construction, cannot move";
|
||||
@@ -566,9 +645,70 @@ namespace stardew_access.Patches
|
||||
if (purchaseAnimalsMenu == null)
|
||||
return;
|
||||
|
||||
int x = (selection.tileX * Game1.tileSize) - Game1.viewport.X;
|
||||
int y = (selection.tileY * Game1.tileSize) - Game1.viewport.Y;
|
||||
int x = (selection.tileX.Value * Game1.tileSize) - Game1.viewport.X;
|
||||
int y = (selection.tileY.Value * Game1.tileSize) - Game1.viewport.Y;
|
||||
|
||||
if (animalBeingPurchasedOrMoved != null && !selection.buildingType.Value.Contains(animalBeingPurchasedOrMoved.buildingTypeILiveIn.Value))
|
||||
{
|
||||
string warn = Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11326", animalBeingPurchasedOrMoved.displayType);
|
||||
MainClass.ScreenReader.Say(warn, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (((AnimalHouse)selection.indoors.Value).isFull())
|
||||
{
|
||||
string warn = Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11321");
|
||||
MainClass.ScreenReader.Say(warn, true);
|
||||
return;
|
||||
}
|
||||
|
||||
purchaseAnimalsMenu.receiveLeftClick(x, y);
|
||||
}
|
||||
|
||||
public static void MoveAnimal(Building? selection)
|
||||
{
|
||||
if (selection == null)
|
||||
return;
|
||||
|
||||
if (animalQueryMenu == null)
|
||||
return;
|
||||
|
||||
if (animalBeingPurchasedOrMoved == null)
|
||||
return;
|
||||
|
||||
// The following code is taken from the game's source code [AnimalQueryMenu.cs::receiveLeftClick]
|
||||
if (selection.buildingType.Value.Contains(animalBeingPurchasedOrMoved.buildingTypeILiveIn.Value))
|
||||
{
|
||||
if (((AnimalHouse)selection.indoors.Value).isFull())
|
||||
{
|
||||
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_BuildingFull");
|
||||
MainClass.ScreenReader.Say(warn, true);
|
||||
return;
|
||||
}
|
||||
if (selection.Equals(animalBeingPurchasedOrMoved.home))
|
||||
{
|
||||
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_AlreadyHome");
|
||||
MainClass.ScreenReader.Say(warn, true);
|
||||
return;
|
||||
}
|
||||
((AnimalHouse)animalBeingPurchasedOrMoved.home.indoors.Value).animalsThatLiveHere.Remove(animalBeingPurchasedOrMoved.myID.Value);
|
||||
if (((AnimalHouse)animalBeingPurchasedOrMoved.home.indoors.Value).animals.ContainsKey(animalBeingPurchasedOrMoved.myID.Value))
|
||||
{
|
||||
((AnimalHouse)selection.indoors.Value).animals.Add(animalBeingPurchasedOrMoved.myID.Value, animalBeingPurchasedOrMoved);
|
||||
((AnimalHouse)animalBeingPurchasedOrMoved.home.indoors.Value).animals.Remove(animalBeingPurchasedOrMoved.myID.Value);
|
||||
}
|
||||
animalBeingPurchasedOrMoved.home = selection;
|
||||
animalBeingPurchasedOrMoved.homeLocation.Value = new Vector2((int)selection.tileX.Value, (int)selection.tileY.Value);
|
||||
((AnimalHouse)selection.indoors.Value).animalsThatLiveHere.Add(animalBeingPurchasedOrMoved.myID.Value);
|
||||
animalBeingPurchasedOrMoved.makeSound();
|
||||
Game1.globalFadeToBlack(animalQueryMenu.finishedPlacingAnimal);
|
||||
}
|
||||
else
|
||||
{
|
||||
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_CantLiveThere");
|
||||
MainClass.ScreenReader.Say(warn, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
360
stardew-access/Patches/BundleMenuPatches.cs
Normal file
360
stardew-access/Patches/BundleMenuPatches.cs
Normal file
@@ -0,0 +1,360 @@
|
||||
using StardewValley;
|
||||
using StardewValley.Locations;
|
||||
using StardewValley.Menus;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
{
|
||||
internal class BundleMenuPatches
|
||||
{
|
||||
internal static string junimoNoteMenuQuery = "";
|
||||
internal static string currentJunimoArea = "";
|
||||
internal static string jojaCDMenuQuery = "";
|
||||
internal static bool isUsingCustomButtons = false;
|
||||
internal static int currentIngredientListItem = -1, currentIngredientInputSlot = -1, currentInventorySlot = -1;
|
||||
|
||||
#region Joja Mart Bundle/Quests
|
||||
internal static void JojaCDMenuPatch(JojaCDMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = "";
|
||||
|
||||
for (int i = 0; i < __instance.checkboxes.Count; i++)
|
||||
{
|
||||
ClickableComponent c = __instance.checkboxes[i];
|
||||
if (!c.containsPoint(x, y))
|
||||
continue;
|
||||
|
||||
if (c.name.Equals("complete"))
|
||||
{
|
||||
toSpeak = $"Completed {getNameFromIndex(i)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
toSpeak = $"{getNameFromIndex(i)} Cost: {__instance.getPriceFromButtonNumber(i)}g Description: {__instance.getDescriptionFromButtonNumber(i)}";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (jojaCDMenuQuery != toSpeak)
|
||||
{
|
||||
jojaCDMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string getNameFromIndex(int i)
|
||||
{
|
||||
string name = i switch
|
||||
{
|
||||
0 => "Bus",
|
||||
1 => "Minecarts",
|
||||
2 => "Bridge",
|
||||
3 => "Greenhouse",
|
||||
4 => "Panning",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
if (name != "")
|
||||
return $"{name} Project";
|
||||
else
|
||||
return "unkown";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Community Center Bundles
|
||||
internal static void JunimoNoteMenuPatch(JunimoNoteMenu __instance, bool ___specificBundlePage, int ___whichArea, Bundle ___currentPageBundle)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
if (!___specificBundlePage)
|
||||
{
|
||||
currentIngredientListItem = -1;
|
||||
isUsingCustomButtons = false;
|
||||
|
||||
string areaName = __instance.scrambledText ? CommunityCenter.getAreaEnglishDisplayNameFromNumber(___whichArea) : CommunityCenter.getAreaDisplayNameFromNumber(___whichArea);
|
||||
string reward = __instance.getRewardNameForArea(___whichArea);
|
||||
|
||||
if (__instance.scrambledText)
|
||||
{
|
||||
string toSpeak = "Scrambled Text";
|
||||
if (junimoNoteMenuQuery != toSpeak)
|
||||
{
|
||||
junimoNoteMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentJunimoArea != areaName)
|
||||
{
|
||||
currentJunimoArea = areaName;
|
||||
MainClass.ScreenReader.Say($"Area {areaName}, {reward}", 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 = MainClass.Config.BundleMenuIngredientsKey.JustPressed(); // For the ingredients
|
||||
bool isCPressed = MainClass.Config.BundleMenuInventoryItemsKey.JustPressed(); // For the items in inventory
|
||||
bool isPPressed = MainClass.Config.BundleMenuPurchaseButtonKey.JustPressed(); // For the Purchase Button
|
||||
bool isVPressed = MainClass.Config.BundleMenuIngredientsInputSlotKey.JustPressed(); // For the ingredient input slots
|
||||
bool isBackPressed = MainClass.Config.BundleMenuBackButtonKey.JustPressed(); // For the back button
|
||||
bool isLeftShiftPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift);
|
||||
|
||||
if (isIPressed && !isUsingCustomButtons)
|
||||
{
|
||||
isUsingCustomButtons = true;
|
||||
JunimoNoteCustomButtons(__instance, ___currentPageBundle, 0, isLeftShiftPressed);
|
||||
Task.Delay(200).ContinueWith(_ => { isUsingCustomButtons = false; });
|
||||
}
|
||||
else if (isVPressed && !isUsingCustomButtons)
|
||||
{
|
||||
isUsingCustomButtons = true;
|
||||
JunimoNoteCustomButtons(__instance, ___currentPageBundle, 1, isLeftShiftPressed);
|
||||
Task.Delay(200).ContinueWith(_ => { isUsingCustomButtons = false; });
|
||||
}
|
||||
else if (isCPressed && !isUsingCustomButtons)
|
||||
{
|
||||
isUsingCustomButtons = true;
|
||||
JunimoNoteCustomButtons(__instance, ___currentPageBundle, 2, isLeftShiftPressed);
|
||||
Task.Delay(200).ContinueWith(_ => { isUsingCustomButtons = false; });
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void JunimoNoteCustomButtons(JunimoNoteMenu __instance, Bundle ___currentPageBundle, int signal, bool isLeftShiftPressed = false)
|
||||
{
|
||||
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.actualInventory.Count >= 0)
|
||||
{
|
||||
int prevSlotIndex = currentInventorySlot;
|
||||
currentInventorySlot = currentInventorySlot + (isLeftShiftPressed ? -1 : 1);
|
||||
if (currentInventorySlot >= __instance.inventory.actualInventory.Count)
|
||||
if (isLeftShiftPressed)
|
||||
currentInventorySlot = __instance.inventory.actualInventory.Count - 1;
|
||||
else
|
||||
currentInventorySlot = 0;
|
||||
|
||||
if (currentInventorySlot < 0)
|
||||
if (isLeftShiftPressed)
|
||||
currentInventorySlot = __instance.inventory.actualInventory.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 = ((StardewValley.Object)item).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}";
|
||||
|
||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[currentInventorySlot]))
|
||||
{
|
||||
toSpeak = $"{toSpeak} not usable here";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
toSpeak = "Empty Slot";
|
||||
}
|
||||
c.snapMouseCursorToCenter();
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -1,10 +1,9 @@
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley;
|
||||
using StardewValley.Menus;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
{
|
||||
internal class ChatManuPatches
|
||||
internal class ChatMenuPatches
|
||||
{
|
||||
private static int currentChatMessageIndex = 0;
|
||||
private static bool isChatRunning = false;
|
||||
@@ -17,19 +16,23 @@ namespace stardew_access.Patches
|
||||
|
||||
if (__instance.chatBox.Selected)
|
||||
{
|
||||
bool isPrevArrowPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.PageUp);
|
||||
bool isNextArrowPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.PageDown);
|
||||
bool isPrevButtonPressed = MainClass.Config.ChatMenuNextKey.JustPressed();
|
||||
bool isNextButtonPressed = MainClass.Config.ChatMenuPreviousKey.JustPressed();
|
||||
|
||||
if (___messages.Count > 0)
|
||||
{
|
||||
#region To narrate previous and next chat messages
|
||||
if (isNextArrowPressed && !isChatRunning)
|
||||
if (isNextButtonPressed && !isChatRunning)
|
||||
{
|
||||
isChatRunning = true;
|
||||
CycleThroughChatMessages(true, ___messages);
|
||||
Task.Delay(200).ContinueWith(_ => { isChatRunning = false; });
|
||||
}
|
||||
else if (isPrevArrowPressed && !isChatRunning)
|
||||
else if (isPrevButtonPressed && !isChatRunning)
|
||||
{
|
||||
isChatRunning = true;
|
||||
CycleThroughChatMessages(false, ___messages);
|
||||
Task.Delay(200).ContinueWith(_ => { isChatRunning = false; });
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -42,44 +45,28 @@ namespace stardew_access.Patches
|
||||
toSpeak += $"{message.message}, ";
|
||||
});
|
||||
if (toSpeak != " ")
|
||||
MainClass.GetScreenReader().SayWithChatChecker(toSpeak, false);
|
||||
MainClass.ScreenReader.SayWithChatChecker(toSpeak, false);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async void CycleThroughChatMessages(bool increase, List<ChatMessage> ___messages)
|
||||
private static void CycleThroughChatMessages(bool increase, List<ChatMessage> ___messages)
|
||||
{
|
||||
isChatRunning = true;
|
||||
string toSpeak = " ";
|
||||
if (increase)
|
||||
{
|
||||
++currentChatMessageIndex;
|
||||
if (currentChatMessageIndex > ___messages.Count - 1)
|
||||
{
|
||||
currentChatMessageIndex = ___messages.Count - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--currentChatMessageIndex;
|
||||
if (currentChatMessageIndex < 0)
|
||||
{
|
||||
currentChatMessageIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
currentChatMessageIndex = (increase) ? (Math.Min(currentChatMessageIndex + 1, ___messages.Count - 1)) : (currentChatMessageIndex = Math.Max(currentChatMessageIndex - 1, 0));
|
||||
|
||||
___messages[currentChatMessageIndex].message.ForEach(message =>
|
||||
{
|
||||
toSpeak += $"{message.message}, ";
|
||||
});
|
||||
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
await Task.Delay(200);
|
||||
isChatRunning = false;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,12 +2,12 @@
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley.Menus;
|
||||
using System.Text;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
{
|
||||
internal class DialoguePatches
|
||||
{
|
||||
internal static string currentLetterText = " ";
|
||||
internal static string currentDialogue = " ";
|
||||
internal static bool isDialogueAppearingFirstTime = true;
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace stardew_access.Patches
|
||||
else
|
||||
toSpeak = response;
|
||||
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -64,7 +64,7 @@ namespace stardew_access.Patches
|
||||
if (currentDialogue != dialogueText)
|
||||
{
|
||||
currentDialogue = dialogueText;
|
||||
MainClass.GetScreenReader().Say(dialogueText, true);
|
||||
MainClass.ScreenReader.Say(dialogueText, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,8 +105,7 @@ namespace stardew_access.Patches
|
||||
else
|
||||
toSpeak = response;
|
||||
|
||||
MainClass.GetMonitor().Log(toSpeak, LogLevel.Debug);
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -114,7 +113,7 @@ namespace stardew_access.Patches
|
||||
if (currentDialogue != dialogueText)
|
||||
{
|
||||
currentDialogue = dialogueText;
|
||||
MainClass.GetScreenReader().Say(dialogueText, true);
|
||||
MainClass.ScreenReader.Say(dialogueText, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,13 +123,13 @@ namespace stardew_access.Patches
|
||||
if (currentDialogue != __instance.getCurrentString())
|
||||
{
|
||||
currentDialogue = __instance.getCurrentString();
|
||||
MainClass.GetScreenReader().Say(__instance.getCurrentString(), true);
|
||||
MainClass.ScreenReader.Say(__instance.getCurrentString(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -149,81 +148,89 @@ namespace stardew_access.Patches
|
||||
#region Skip narrating hover text for certain menus
|
||||
if (Game1.activeClickableMenu is TitleMenu && !(((TitleMenu)Game1.activeClickableMenu).GetChildMenu() is CharacterCustomization))
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is LetterViewerMenu || Game1.activeClickableMenu is QuestLog)
|
||||
else if (Game1.activeClickableMenu is LetterViewerMenu || Game1.activeClickableMenu is QuestLog)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is Billboard)
|
||||
else if (Game1.activeClickableMenu is Billboard)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is GeodeMenu)
|
||||
else if (Game1.activeClickableMenu is GeodeMenu)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is InventoryPage)
|
||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is InventoryPage)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is CraftingPage)
|
||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is CraftingPage)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is OptionsPage)
|
||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is OptionsPage)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is ExitPage)
|
||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is ExitPage)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is SocialPage)
|
||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is SocialPage)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is ItemGrabMenu)
|
||||
else if (Game1.activeClickableMenu is ItemGrabMenu)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is ShopMenu)
|
||||
else if (Game1.activeClickableMenu is ShopMenu)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is ConfirmationDialog)
|
||||
else if (Game1.activeClickableMenu is ConfirmationDialog)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is JunimoNoteMenu)
|
||||
else if (Game1.activeClickableMenu is JunimoNoteMenu)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is CarpenterMenu)
|
||||
else if (Game1.activeClickableMenu is CarpenterMenu)
|
||||
return;
|
||||
|
||||
if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
||||
else if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is CraftingPage)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is AnimalQueryMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is ConfirmationDialog)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is ReadyCheckDialog)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is JojaCDMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is TailoringMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is PondQueryMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is ForgeMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is ItemListMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is FieldOfficeMenu)
|
||||
return;
|
||||
else if (Game1.activeClickableMenu is MuseumMenu)
|
||||
return;
|
||||
#endregion
|
||||
|
||||
StringBuilder toSpeak = new StringBuilder(" ");
|
||||
string toSpeak = " ";
|
||||
|
||||
#region Add item count before title
|
||||
if (hoveredItem != null && hoveredItem.HasBeenInInventory)
|
||||
{
|
||||
int count = hoveredItem.Stack;
|
||||
if (count > 1)
|
||||
toSpeak.Append($"{count} ");
|
||||
toSpeak = $"{toSpeak} {count} ";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add title if any
|
||||
if (boldTitleText != null)
|
||||
toSpeak.Append($"{boldTitleText}\n");
|
||||
toSpeak = $"{toSpeak} {boldTitleText}\n";
|
||||
#endregion
|
||||
|
||||
#region Add quality of item
|
||||
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).quality > 0)
|
||||
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).Quality > 0)
|
||||
{
|
||||
int quality = ((StardewValley.Object)hoveredItem).quality;
|
||||
int quality = ((StardewValley.Object)hoveredItem).Quality;
|
||||
if (quality == 1)
|
||||
{
|
||||
toSpeak.Append("Silver quality");
|
||||
toSpeak = $"{toSpeak} Silver quality";
|
||||
}
|
||||
else if (quality == 2 || quality == 3)
|
||||
{
|
||||
toSpeak.Append("Gold quality");
|
||||
toSpeak = $"{toSpeak} Gold quality";
|
||||
}
|
||||
else if (quality >= 4)
|
||||
{
|
||||
toSpeak.Append("Iridium quality");
|
||||
toSpeak = $"{toSpeak} Iridium quality";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -234,26 +241,29 @@ namespace stardew_access.Patches
|
||||
string itemName = Game1.objectInformation[extraItemToShowIndex].Split('/')[0];
|
||||
|
||||
if (extraItemToShowAmount != -1)
|
||||
toSpeak.Append($"Required: {extraItemToShowAmount} {itemName}");
|
||||
toSpeak = $"{toSpeak} Required: {extraItemToShowAmount} {itemName}";
|
||||
else
|
||||
toSpeak.Append($"Required: {itemName}");
|
||||
toSpeak = $"{toSpeak} Required: {itemName}";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add money
|
||||
if (moneyAmountToDisplayAtBottom != -1)
|
||||
toSpeak.Append($"\nCost: {moneyAmountToDisplayAtBottom}g\n");
|
||||
toSpeak = $"{toSpeak} \nCost: {moneyAmountToDisplayAtBottom}g\n";
|
||||
#endregion
|
||||
|
||||
#region Add the base text
|
||||
toSpeak.Append(text);
|
||||
if (text == "???")
|
||||
toSpeak = "unknown";
|
||||
else
|
||||
toSpeak = $"{toSpeak} {text}";
|
||||
#endregion
|
||||
|
||||
#region Add crafting ingredients
|
||||
if (craftingIngredients != null)
|
||||
{
|
||||
toSpeak.Append($"\n{craftingIngredients.description}");
|
||||
toSpeak.Append("\nIngredients\n");
|
||||
toSpeak = $"{toSpeak} \n{craftingIngredients.description}";
|
||||
toSpeak = $"{toSpeak} \nIngredients\n";
|
||||
|
||||
craftingIngredients.recipeList.ToList().ForEach(recipe =>
|
||||
{
|
||||
@@ -261,7 +271,7 @@ namespace stardew_access.Patches
|
||||
int item = recipe.Key;
|
||||
string name = craftingIngredients.getNameFromIndex(item);
|
||||
|
||||
toSpeak.Append($" ,{count} {name}");
|
||||
toSpeak = $"{toSpeak} ,{count} {name}";
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
@@ -270,11 +280,11 @@ namespace stardew_access.Patches
|
||||
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).Edibility != -300)
|
||||
{
|
||||
int stamina_recovery = ((StardewValley.Object)hoveredItem).staminaRecoveredOnConsumption();
|
||||
toSpeak.Append($"{stamina_recovery} Energy\n");
|
||||
toSpeak = $"{toSpeak} {stamina_recovery} Energy\n";
|
||||
if (stamina_recovery >= 0)
|
||||
{
|
||||
int health_recovery = ((StardewValley.Object)hoveredItem).healthRecoveredOnConsumption();
|
||||
toSpeak.Append($"{health_recovery} Health");
|
||||
toSpeak = $"{toSpeak} {health_recovery} Health";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -293,7 +303,7 @@ namespace stardew_access.Patches
|
||||
{
|
||||
int count = int.Parse(buffName.Substring(0, buffName.IndexOf(' ')));
|
||||
if (count != 0)
|
||||
toSpeak.Append($"{buffName}\n");
|
||||
toSpeak = $"{toSpeak} {buffName}\n";
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
@@ -307,15 +317,110 @@ namespace stardew_access.Patches
|
||||
if (toSpeak.ToString() != " ")
|
||||
{
|
||||
if (Context.IsPlayerFree)
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak.ToString(), true); // Normal Checker
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak.ToString(), true); // Normal Checker
|
||||
else
|
||||
MainClass.GetScreenReader().SayWithMenuChecker(toSpeak.ToString(), true); // Menu Checker
|
||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak.ToString(), true); // Menu Checker
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LetterViewerMenuPatch(LetterViewerMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!__instance.IsActive())
|
||||
return;
|
||||
|
||||
NarrateLetterContent(__instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void NarrateLetterContent(LetterViewerMenu __instance)
|
||||
{
|
||||
int x = Game1.getMousePosition().X, y = Game1.getMousePosition().Y;
|
||||
#region Texts in the letter
|
||||
string message = __instance.mailMessage[__instance.page];
|
||||
|
||||
string toSpeak = $"{message}";
|
||||
|
||||
if (__instance.ShouldShowInteractable())
|
||||
{
|
||||
if (__instance.moneyIncluded > 0)
|
||||
{
|
||||
string moneyText = Game1.content.LoadString("Strings\\UI:LetterViewer_MoneyIncluded", __instance.moneyIncluded);
|
||||
toSpeak += $"\t\n\t ,Included money: {moneyText}";
|
||||
}
|
||||
else if (__instance.learnedRecipe != null && __instance.learnedRecipe.Length > 0)
|
||||
{
|
||||
string recipeText = Game1.content.LoadString("Strings\\UI:LetterViewer_LearnedRecipe", __instance.cookingOrCrafting);
|
||||
toSpeak += $"\t\n\t ,Learned Recipe: {recipeText}";
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLetterText != toSpeak)
|
||||
{
|
||||
currentLetterText = toSpeak;
|
||||
|
||||
// snap mouse to accept quest button
|
||||
if (__instance.acceptQuestButton != null && __instance.questID != -1)
|
||||
{
|
||||
toSpeak += "\t\n Left click to accept quest.";
|
||||
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
||||
}
|
||||
if (__instance.mailMessage.Count > 1)
|
||||
toSpeak = $"Page {__instance.page + 1} of {__instance.mailMessage.Count}:\n\t{toSpeak}";
|
||||
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Narrate items given in the mail
|
||||
if (__instance.ShouldShowInteractable())
|
||||
{
|
||||
foreach (ClickableComponent c in __instance.itemsToGrab)
|
||||
{
|
||||
if (c.item == null)
|
||||
continue;
|
||||
|
||||
string name = c.item.DisplayName;
|
||||
|
||||
if (c.containsPoint(x, y))
|
||||
MainClass.ScreenReader.SayWithChecker($"Left click to collect {name}", false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Narrate buttons
|
||||
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
||||
MainClass.ScreenReader.SayWithChecker($"Previous page button", false);
|
||||
|
||||
if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
||||
MainClass.ScreenReader.SayWithChecker($"Next page button", false);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal static void drawAboveAlwaysFrontLayerPatch(NPC __instance, string ___textAboveHead, int ___textAboveHeadTimer)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (___textAboveHeadTimer > 2900 && ___textAboveHead != null)
|
||||
{
|
||||
MainClass.ScreenReader.SayWithChecker($"{__instance.displayName} says {___textAboveHead}", true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Error in patch:NPCShowTextAboveHeadPatch \n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
417
stardew-access/Patches/DonationMenuPatches.cs
Normal file
417
stardew-access/Patches/DonationMenuPatches.cs
Normal file
@@ -0,0 +1,417 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using StardewValley;
|
||||
using StardewValley.Locations;
|
||||
using StardewValley.Menus;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
{
|
||||
internal class DonationMenuPatches
|
||||
{
|
||||
internal static string museumQueryKey = " ";
|
||||
internal static string fieldOfficeMenuQuery = " ";
|
||||
private static bool isMoving = false;
|
||||
private static (int x, int y)[] donationTiles =
|
||||
{
|
||||
(26,5),(26,6),(26,7),(26,8),(26,9),(26,10),(26,11),
|
||||
(29,5),(30,5),(31,5),(32,5),(33,5),(34,5),(35,5),(36,5),
|
||||
(28,6),(29,6),(30,6),(31,6),(32,6),(33,6),(34,6),(35,6),(36,6),(37,6),
|
||||
(28,9),(29,9),(30,9),(31,9),(32,9),(33,9),(34,9),(35,9),(36,9),
|
||||
(28,10),(29,10),(30,10),(31,10),(32,10),(33,10),(34,10),(35,10),(36,10),
|
||||
(30,13),(31,13),(32,13),(33,13),(34,13),
|
||||
(30,14),(31,14),(32,14),(33,14),(34,14),
|
||||
(28,15),(29,15),(30,15),(31,15),(32,15),(33,15),(34,15),(35,15),(36,15),
|
||||
(28,16),(29,16),(30,16),(31,16),(32,16),(33,16),(34,16),(35,16),(36,16),
|
||||
(39,6),(40,6),(41,6),(42,6),(43,6),(44,6),(45,6),(46,6),
|
||||
(39,7),(40,7),(41,7),(42,7),(43,7),(44,7),(45,7),(46,7),
|
||||
(48,5),(48,6),(48,7),
|
||||
(42,15),(43,15),(44,15),(45,15),(46,15),(47,15),
|
||||
(42,16),(43,16),(44,16),(45,16),(46,16),(47,16),
|
||||
};
|
||||
|
||||
#region Museum
|
||||
|
||||
internal static bool MuseumMenuKeyPressPatch()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isMoving)
|
||||
return false;
|
||||
|
||||
if (!isMoving)
|
||||
{
|
||||
isMoving = true;
|
||||
Task.Delay(200).ContinueWith(_ => { isMoving = false; });
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static void MuseumMenuPatch(MuseumMenu __instance, bool ___holdingMuseumPiece)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
|
||||
if (__instance.heldItem != null)
|
||||
{
|
||||
// Museum Inventory
|
||||
string toSpeak = " ";
|
||||
int tileX = (int)(Utility.ModifyCoordinateFromUIScale(x) + (float)Game1.viewport.X) / 64;
|
||||
int tileY = (int)(Utility.ModifyCoordinateFromUIScale(y) + (float)Game1.viewport.Y) / 64;
|
||||
LibraryMuseum libraryMuseum = (LibraryMuseum)Game1.currentLocation;
|
||||
|
||||
if (libraryMuseum.isTileSuitableForMuseumPiece(tileX, tileY))
|
||||
toSpeak = $"slot {tileX}x {tileY}y";
|
||||
|
||||
if (museumQueryKey != toSpeak)
|
||||
{
|
||||
museumQueryKey = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player Inventory
|
||||
int i = narrateHoveredItemInInventory(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y);
|
||||
if (i != -9999)
|
||||
{
|
||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); // For donating hovered item
|
||||
|
||||
if (isPrimaryInfoKeyPressed && __instance.inventory.actualInventory[i] != null)
|
||||
{
|
||||
foreach (var tile in donationTiles)
|
||||
{
|
||||
#region Manually donates the hovered item (https://github.com/veywrn/StardewValley/blob/3ff171b6e9e6839555d7881a391b624ccd820a83/StardewValley/Menus/MuseumMenu.cs#L206-L247)
|
||||
int tileX = tile.x;
|
||||
int tileY = tile.y;
|
||||
|
||||
if (((LibraryMuseum)Game1.currentLocation).isTileSuitableForMuseumPiece(tileX, tileY) && ((LibraryMuseum)Game1.currentLocation).isItemSuitableForDonation(__instance.inventory.actualInventory[i]))
|
||||
{
|
||||
int objectID = __instance.inventory.actualInventory[i].ParentSheetIndex;
|
||||
int rewardsCount = ((LibraryMuseum)Game1.currentLocation).getRewardsForPlayer(Game1.player).Count;
|
||||
((LibraryMuseum)Game1.currentLocation).museumPieces.Add(new Vector2(tileX, tileY), ((StardewValley.Object)__instance.inventory.actualInventory[i]).ParentSheetIndex);
|
||||
Game1.playSound("stoneStep");
|
||||
if (((LibraryMuseum)Game1.currentLocation).getRewardsForPlayer(Game1.player).Count > rewardsCount)
|
||||
{
|
||||
Game1.playSound("reward");
|
||||
}
|
||||
else
|
||||
{
|
||||
Game1.playSound("newArtifact");
|
||||
}
|
||||
Game1.player.completeQuest(24);
|
||||
__instance.inventory.actualInventory[i].Stack--;
|
||||
if (__instance.inventory.actualInventory[i].Stack <= 0)
|
||||
{
|
||||
__instance.inventory.actualInventory[i] = null;
|
||||
}
|
||||
int pieces = ((LibraryMuseum)Game1.currentLocation).museumPieces.Count();
|
||||
Game1.stats.checkForArchaeologyAchievements();
|
||||
switch (pieces)
|
||||
{
|
||||
case 95:
|
||||
globalChatInfoMessage("MuseumComplete", Game1.player.farmName.Value);
|
||||
break;
|
||||
case 40:
|
||||
globalChatInfoMessage("Museum40", Game1.player.farmName.Value);
|
||||
break;
|
||||
default:
|
||||
globalChatInfoMessage("donation", Game1.player.Name, "object:" + objectID);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
if (museumQueryKey != $"ok button")
|
||||
{
|
||||
museumQueryKey = $"ok button";
|
||||
MainClass.ScreenReader.Say("ok button", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the index of the hovered item or -9999
|
||||
internal static int narrateHoveredItemInInventory(InventoryMenu inventoryMenu, List<ClickableComponent> inventory, IList<Item> actualInventory, int x, int y)
|
||||
{
|
||||
#region Narrate hovered item
|
||||
for (int i = 0; i < inventory.Count; i++)
|
||||
{
|
||||
if (inventory[i].containsPoint(x, y))
|
||||
{
|
||||
string toSpeak = "";
|
||||
if ((i + 1) <= actualInventory.Count)
|
||||
{
|
||||
if (actualInventory[i] != null)
|
||||
{
|
||||
string name = actualInventory[i].DisplayName;
|
||||
int stack = actualInventory[i].Stack;
|
||||
string quality = "";
|
||||
|
||||
#region Add quality of item
|
||||
if (actualInventory[i] is StardewValley.Object && ((StardewValley.Object)actualInventory[i]).Quality > 0)
|
||||
{
|
||||
int qualityIndex = ((StardewValley.Object)actualInventory[i]).Quality;
|
||||
if (qualityIndex == 1)
|
||||
{
|
||||
quality = "Silver quality";
|
||||
}
|
||||
else if (qualityIndex == 2 || qualityIndex == 3)
|
||||
{
|
||||
quality = "Gold quality";
|
||||
}
|
||||
else if (qualityIndex >= 4)
|
||||
{
|
||||
quality = "Iridium quality";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (inventoryMenu.highlightMethod(inventoryMenu.actualInventory[i]))
|
||||
name = $"Donatable {name}";
|
||||
|
||||
if (stack > 1)
|
||||
toSpeak = $"{stack} {name} {quality}";
|
||||
else
|
||||
toSpeak = $"{name} {quality}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// For empty slot
|
||||
toSpeak = "Empty Slot";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For empty slot
|
||||
toSpeak = "Empty Slot";
|
||||
}
|
||||
|
||||
if (museumQueryKey != $"{toSpeak}:{i}")
|
||||
{
|
||||
museumQueryKey = $"{toSpeak}:{i}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
return -9999;
|
||||
}
|
||||
|
||||
#region These methods are taken from the game's source code, https://github.com/veywrn/StardewValley/blob/3ff171b6e9e6839555d7881a391b624ccd820a83/StardewValley/Multiplayer.cs#L1331-L1395
|
||||
internal static void globalChatInfoMessage(string messageKey, params string[] args)
|
||||
{
|
||||
if (Game1.IsMultiplayer || Game1.multiplayerMode != 0)
|
||||
{
|
||||
receiveChatInfoMessage(Game1.player, messageKey, args);
|
||||
sendChatInfoMessage(messageKey, args);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void sendChatInfoMessage(string messageKey, params string[] args)
|
||||
{
|
||||
if (Game1.IsClient)
|
||||
{
|
||||
Game1.client.sendMessage(15, messageKey, args);
|
||||
}
|
||||
else if (Game1.IsServer)
|
||||
{
|
||||
foreach (long id in Game1.otherFarmers.Keys)
|
||||
{
|
||||
Game1.server.sendMessage(id, 15, Game1.player, messageKey, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void receiveChatInfoMessage(Farmer sourceFarmer, string messageKey, string[] args)
|
||||
{
|
||||
if (Game1.chatBox != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] processedArgs = args.Select(delegate (string arg)
|
||||
{
|
||||
if (arg.StartsWith("achievement:"))
|
||||
{
|
||||
int key = Convert.ToInt32(arg.Substring("achievement:".Length));
|
||||
return Game1.content.Load<Dictionary<int, string>>("Data\\Achievements")[key].Split('^')[0];
|
||||
}
|
||||
return arg.StartsWith("object:") ? new StardewValley.Object(Convert.ToInt32(arg.Substring("object:".Length)), 1).DisplayName : arg;
|
||||
}).ToArray();
|
||||
ChatBox chatBox = Game1.chatBox;
|
||||
LocalizedContentManager content = Game1.content;
|
||||
string path = "Strings\\UI:Chat_" + messageKey;
|
||||
object[] substitutions = processedArgs;
|
||||
chatBox.addInfoMessage(content.LoadString(path, substitutions));
|
||||
}
|
||||
catch (ContentLoadException)
|
||||
{
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Field Office
|
||||
|
||||
internal static void FieldOfficeMenuPatch(FieldOfficeMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = " ";
|
||||
|
||||
if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Trashcan";
|
||||
}
|
||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "ok button";
|
||||
}
|
||||
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "drop item";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < __instance.inventory.inventory.Count; i++)
|
||||
{
|
||||
if (!__instance.inventory.inventory[i].containsPoint(x, y))
|
||||
continue;
|
||||
|
||||
if (__instance.inventory.actualInventory[i] == null)
|
||||
toSpeak = "Empty slot";
|
||||
else
|
||||
{
|
||||
toSpeak = $"{__instance.inventory.actualInventory[i].Stack} {__instance.inventory.actualInventory[i].DisplayName}";
|
||||
|
||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[i]))
|
||||
{
|
||||
toSpeak = $"{toSpeak} not usable here";
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldOfficeMenuQuery != $"{toSpeak}:{i}")
|
||||
{
|
||||
fieldOfficeMenuQuery = $"{toSpeak}:{i}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < __instance.pieceHolders.Count; i++)
|
||||
{
|
||||
if (!__instance.pieceHolders[i].containsPoint(x, y))
|
||||
continue;
|
||||
|
||||
if (__instance.pieceHolders[i].item == null)
|
||||
toSpeak = i switch
|
||||
{
|
||||
0 => "Center skeleton slot",
|
||||
1 => "Center skeleton slot",
|
||||
2 => "Center skeleton slot",
|
||||
3 => "Center skeleton slot",
|
||||
4 => "Center skeleton slot",
|
||||
5 => "Center skeleton slot",
|
||||
6 => "Snake slot",
|
||||
7 => "Snake slot",
|
||||
8 => "Snake slot",
|
||||
9 => "Bat slot",
|
||||
10 => "Frog slot",
|
||||
_ => "Donation slot"
|
||||
};
|
||||
else
|
||||
toSpeak = $"Slot {i + 1} finished: {__instance.pieceHolders[i].item.DisplayName}";
|
||||
|
||||
if (__instance.heldItem != null && __instance.pieceHolders[i].item == null)
|
||||
{
|
||||
int highlight = getPieceIndexForDonationItem(__instance.heldItem.ParentSheetIndex);
|
||||
if (highlight != -1 && highlight == i)
|
||||
toSpeak += "Donatable ";
|
||||
}
|
||||
|
||||
if (fieldOfficeMenuQuery != $"{toSpeak}:{i}")
|
||||
{
|
||||
fieldOfficeMenuQuery = $"{toSpeak}:{i}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldOfficeMenuQuery != toSpeak)
|
||||
{
|
||||
fieldOfficeMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
|
||||
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||
Game1.playSound("drop_item");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static int getPieceIndexForDonationItem(int itemIndex)
|
||||
{
|
||||
switch (itemIndex)
|
||||
{
|
||||
case 820:
|
||||
return 5;
|
||||
case 821:
|
||||
return 4;
|
||||
case 822:
|
||||
return 3;
|
||||
case 823:
|
||||
return 0;
|
||||
case 824:
|
||||
return 1;
|
||||
case 825:
|
||||
return 8;
|
||||
case 826:
|
||||
return 7;
|
||||
case 827:
|
||||
return 9;
|
||||
case 828:
|
||||
return 10;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -2,16 +2,366 @@
|
||||
using stardew_access.Features;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley.Buildings;
|
||||
using StardewValley.Menus;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
{
|
||||
internal class MenuPatches
|
||||
{
|
||||
private static string currentLetterText = " ";
|
||||
private static string currentLevelUpTitle = " ";
|
||||
internal static string currentLevelUpTitle = " ";
|
||||
internal static bool firstTimeInNamingMenu = true;
|
||||
internal static bool isNarratingPondInfo = false;
|
||||
internal static string tailoringMenuQuery = " ";
|
||||
internal static string pondQueryMenuQuery = " ";
|
||||
internal static string forgeMenuQuery = " ";
|
||||
internal static string itemListMenuQuery = " ";
|
||||
public static Vector2? prevTile = null;
|
||||
|
||||
internal static void ItemListMenuPatch(ItemListMenu __instance, string ___title, int ___currentTab, int ___totalValueOfItems, List<Item> ___itemsToList)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = " ", currentList = " ";
|
||||
|
||||
for (int i = ___currentTab * __instance.itemsPerCategoryPage; i < ___currentTab * __instance.itemsPerCategoryPage + __instance.itemsPerCategoryPage; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
currentList = ___title;
|
||||
|
||||
if (___itemsToList.Count > i)
|
||||
{
|
||||
if (___itemsToList[i] == null)
|
||||
{
|
||||
currentList = $"{currentList}, \n" + Game1.content.LoadString("Strings\\UI:ItemList_ItemsLostValue", ___totalValueOfItems);
|
||||
continue;
|
||||
}
|
||||
|
||||
currentList = $"{currentList}, \n {___itemsToList[i].Stack} {___itemsToList[i].DisplayName}";
|
||||
}
|
||||
}
|
||||
|
||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
toSpeak = $"Page {___currentTab + 1} of {((int)___itemsToList.Count / __instance.itemsPerCategoryPage) + 1} \n {currentList} \n ok button";
|
||||
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
||||
toSpeak = "Next page button";
|
||||
else if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
||||
toSpeak = "Previous page button";
|
||||
|
||||
if (itemListMenuQuery != toSpeak)
|
||||
{
|
||||
itemListMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ForgeMenuPatch(ForgeMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = " ";
|
||||
|
||||
if (__instance.leftIngredientSpot != null && __instance.leftIngredientSpot.containsPoint(x, y))
|
||||
{
|
||||
if (__instance.leftIngredientSpot.item == null)
|
||||
{
|
||||
toSpeak = "Input weapon or tool here";
|
||||
}
|
||||
else
|
||||
{
|
||||
Item item = __instance.leftIngredientSpot.item;
|
||||
toSpeak = $"Weapon slot: {item.Stack} {item.DisplayName}";
|
||||
}
|
||||
}
|
||||
else if (__instance.rightIngredientSpot != null && __instance.rightIngredientSpot.containsPoint(x, y))
|
||||
{
|
||||
if (__instance.rightIngredientSpot.item == null)
|
||||
{
|
||||
toSpeak = "Input gemstone here";
|
||||
}
|
||||
else
|
||||
{
|
||||
Item item = __instance.rightIngredientSpot.item;
|
||||
toSpeak = $"Gemstone slot: {item.Stack} {item.DisplayName}";
|
||||
}
|
||||
}
|
||||
else if (__instance.startTailoringButton != null && __instance.startTailoringButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Star forging button";
|
||||
}
|
||||
else if (__instance.unforgeButton != null && __instance.unforgeButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Unforge button";
|
||||
}
|
||||
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Trashcan";
|
||||
}
|
||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "ok button";
|
||||
}
|
||||
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "drop item";
|
||||
}
|
||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[0].containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Left ring Slot";
|
||||
|
||||
if (Game1.player.leftRing.Value != null)
|
||||
toSpeak = $"{toSpeak}: {Game1.player.leftRing.Value.DisplayName}";
|
||||
}
|
||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[1].containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Right ring Slot";
|
||||
|
||||
if (Game1.player.rightRing.Value != null)
|
||||
toSpeak = $"{toSpeak}: {Game1.player.rightRing.Value.DisplayName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < __instance.inventory.inventory.Count; i++)
|
||||
{
|
||||
if (!__instance.inventory.inventory[i].containsPoint(x, y))
|
||||
continue;
|
||||
|
||||
if (__instance.inventory.actualInventory[i] == null)
|
||||
toSpeak = "Empty slot";
|
||||
else
|
||||
{
|
||||
toSpeak = $"{__instance.inventory.actualInventory[i].Stack} {__instance.inventory.actualInventory[i].DisplayName}";
|
||||
|
||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[i]))
|
||||
{
|
||||
toSpeak = $"{toSpeak} not usable here";
|
||||
}
|
||||
}
|
||||
|
||||
if (forgeMenuQuery != $"{toSpeak}:{i}")
|
||||
{
|
||||
forgeMenuQuery = $"{toSpeak}:{i}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (forgeMenuQuery != toSpeak)
|
||||
{
|
||||
forgeMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
|
||||
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||
Game1.playSound("drop_item");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void PondQueryMenuPatch(PondQueryMenu __instance, StardewValley.Object ____fishItem, FishPond ____pond, string ____statusText, bool ___confirmingEmpty)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||
string toSpeak = " ", extra = "";
|
||||
|
||||
if (___confirmingEmpty)
|
||||
{
|
||||
if (__instance.yesButton != null && __instance.yesButton.containsPoint(x, y))
|
||||
toSpeak = "Confirm button";
|
||||
else if (__instance.noButton != null && __instance.noButton.containsPoint(x, y))
|
||||
toSpeak = "Cancel button";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isPrimaryInfoKeyPressed && !isNarratingPondInfo)
|
||||
{
|
||||
string pond_name_text = Game1.content.LoadString("Strings\\UI:PondQuery_Name", ____fishItem.DisplayName);
|
||||
string population_text = Game1.content.LoadString("Strings\\UI:PondQuery_Population", string.Concat(____pond.FishCount), ____pond.maxOccupants.Value);
|
||||
bool has_unresolved_needs = ____pond.neededItem.Value != null && ____pond.HasUnresolvedNeeds() && !____pond.hasCompletedRequest.Value;
|
||||
string bring_text = "";
|
||||
|
||||
if (has_unresolved_needs && ____pond.neededItem.Value != null)
|
||||
bring_text = Game1.content.LoadString("Strings\\UI:PondQuery_StatusRequest_Bring") + $": {____pond.neededItemCount} {____pond.neededItem.Value.DisplayName}";
|
||||
|
||||
extra = $"{pond_name_text} {population_text} {bring_text} Status: {____statusText}";
|
||||
pondQueryMenuQuery = " ";
|
||||
|
||||
isNarratingPondInfo = true;
|
||||
Task.Delay(200).ContinueWith(_ => { isNarratingPondInfo = false; });
|
||||
}
|
||||
|
||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
toSpeak = "Ok button";
|
||||
else if (__instance.changeNettingButton != null && __instance.changeNettingButton.containsPoint(x, y))
|
||||
toSpeak = "Change netting button";
|
||||
else if (__instance.emptyButton != null && __instance.emptyButton.containsPoint(x, y))
|
||||
toSpeak = "Empty pond button";
|
||||
}
|
||||
|
||||
if (pondQueryMenuQuery != toSpeak)
|
||||
{
|
||||
pondQueryMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void TailoringMenuPatch(TailoringMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = " ";
|
||||
|
||||
if (__instance.leftIngredientSpot != null && __instance.leftIngredientSpot.containsPoint(x, y))
|
||||
{
|
||||
if (__instance.leftIngredientSpot.item == null)
|
||||
{
|
||||
toSpeak = "Input cloth here";
|
||||
}
|
||||
else
|
||||
{
|
||||
Item item = __instance.leftIngredientSpot.item;
|
||||
toSpeak = $"Cloth slot: {item.Stack} {item.DisplayName}";
|
||||
}
|
||||
}
|
||||
else if (__instance.rightIngredientSpot != null && __instance.rightIngredientSpot.containsPoint(x, y))
|
||||
{
|
||||
if (__instance.rightIngredientSpot.item == null)
|
||||
{
|
||||
toSpeak = "Input ingredient here";
|
||||
}
|
||||
else
|
||||
{
|
||||
Item item = __instance.rightIngredientSpot.item;
|
||||
toSpeak = $"Ingredient slot: {item.Stack} {item.DisplayName}";
|
||||
}
|
||||
}
|
||||
else if (__instance.startTailoringButton != null && __instance.startTailoringButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Star tailoring button";
|
||||
}
|
||||
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Trashcan";
|
||||
}
|
||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "ok button";
|
||||
}
|
||||
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "drop item";
|
||||
}
|
||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[0].containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Hat Slot";
|
||||
|
||||
if (Game1.player.hat.Value != null)
|
||||
toSpeak = $"{toSpeak}: {Game1.player.hat.Value.DisplayName}";
|
||||
}
|
||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[1].containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Shirt Slot";
|
||||
|
||||
if (Game1.player.shirtItem.Value != null)
|
||||
toSpeak = $"{toSpeak}: {Game1.player.shirtItem.Value.DisplayName}";
|
||||
}
|
||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[2].containsPoint(x, y))
|
||||
{
|
||||
toSpeak = "Pants Slot";
|
||||
|
||||
if (Game1.player.pantsItem.Value != null)
|
||||
toSpeak = $"{toSpeak}: {Game1.player.pantsItem.Value.DisplayName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < __instance.inventory.inventory.Count; i++)
|
||||
{
|
||||
if (!__instance.inventory.inventory[i].containsPoint(x, y))
|
||||
continue;
|
||||
|
||||
if (__instance.inventory.actualInventory[i] == null)
|
||||
toSpeak = "Empty slot";
|
||||
else
|
||||
{
|
||||
toSpeak = $"{__instance.inventory.actualInventory[i].Stack} {__instance.inventory.actualInventory[i].DisplayName}";
|
||||
|
||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[i]))
|
||||
{
|
||||
toSpeak = $"{toSpeak} not usable here";
|
||||
}
|
||||
}
|
||||
|
||||
if (tailoringMenuQuery != $"{toSpeak}:{i}")
|
||||
{
|
||||
tailoringMenuQuery = $"{toSpeak}:{i}";
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tailoringMenuQuery != toSpeak)
|
||||
{
|
||||
tailoringMenuQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
|
||||
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||
Game1.playSound("drop_item");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ChooseFromListMenuPatch(ChooseFromListMenu __instance, List<string> ___options, int ___index, bool ___isJukebox)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = "";
|
||||
|
||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
toSpeak = "Select " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[___index]) : ___options[___index]) + " button";
|
||||
else if (__instance.cancelButton != null && __instance.cancelButton.containsPoint(x, y))
|
||||
toSpeak = "Cancel button";
|
||||
else if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
||||
toSpeak = "Previous option: " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[Math.Max(0, ___index - 1)]) : ___options[Math.Max(0, ___index - 1)]) + " button";
|
||||
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
||||
toSpeak = "Next option: " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[Math.Min(___options.Count, ___index + 1)]) : ___options[Math.Min(___options.Count, ___index + 1)]) + " button";
|
||||
|
||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool PlaySoundPatch(string cueName)
|
||||
{
|
||||
try
|
||||
@@ -24,8 +374,8 @@ namespace stardew_access.Patches
|
||||
|
||||
if (cueName == "grassyStep" || cueName == "sandyStep" || cueName == "snowyStep" || cueName == "stoneStep" || cueName == "thudStep" || cueName == "woodyStep")
|
||||
{
|
||||
Vector2 nextTile = CurrentPlayer.getNextTile();
|
||||
if (ReadTile.isCollidingAtTile((int)nextTile.X, (int)nextTile.Y))
|
||||
Vector2 nextTile = CurrentPlayer.FacingTile;
|
||||
if (TileInfo.isCollidingAtTile((int)nextTile.X, (int)nextTile.Y))
|
||||
{
|
||||
if (prevTile != nextTile)
|
||||
{
|
||||
@@ -38,7 +388,7 @@ namespace stardew_access.Patches
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -48,17 +398,17 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY(); // Mouse x and y position
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
|
||||
if (__instance.nextPageButton != null && __instance.nextPageButton.containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker($"Next Page Button", true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker($"Next Page Button", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (__instance.previousPageButton != null && __instance.previousPageButton.containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker($"Previous Page Button", true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker($"Previous Page Button", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,14 +416,14 @@ namespace stardew_access.Patches
|
||||
{
|
||||
if (__instance.languages[i].containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker($"{__instance.languageList[i]} Button", true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker($"{__instance.languageList[i]} Button", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,35 +431,81 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY(); // Mouse x and y position
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
for (int i = 0; i < ___elevators.Count; i++)
|
||||
{
|
||||
if (___elevators[i].containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker($"{___elevators[i].name} level", true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker($"{___elevators[i].name} level", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void NamingMenuPatch(NamingMenu __instance, string title, TextBox ___textBox)
|
||||
internal static void TitleTextInputMenuPatch(TitleTextInputMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
__instance.textBoxCC.snapMouseCursor();
|
||||
___textBox.SelectMe();
|
||||
string toSpeak = $"{title}";
|
||||
string toSpeak = "";
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
if (__instance.pasteButton != null && __instance.pasteButton.containsPoint(x, y))
|
||||
toSpeak = $"Paste button";
|
||||
|
||||
if (toSpeak != "")
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void NamingMenuPatch(NamingMenu __instance, TextBox ___textBox, string ___title)
|
||||
{
|
||||
try
|
||||
{
|
||||
string toSpeak = "";
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
||||
|
||||
if (firstTimeInNamingMenu)
|
||||
{
|
||||
firstTimeInNamingMenu = false;
|
||||
___textBox.Selected = false;
|
||||
}
|
||||
|
||||
if (___textBox.Selected)
|
||||
{
|
||||
___textBox.Update();
|
||||
toSpeak = ___textBox.Text;
|
||||
|
||||
if (isEscPressed)
|
||||
{
|
||||
___textBox.Selected = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
||||
toSpeak = $"{___title} text box";
|
||||
else if (__instance.doneNamingButton != null && __instance.doneNamingButton.containsPoint(x, y))
|
||||
toSpeak = $"Done naming button";
|
||||
else if (__instance.randomButton != null && __instance.randomButton.containsPoint(x, y))
|
||||
toSpeak = $"Random button";
|
||||
}
|
||||
|
||||
if (toSpeak != "")
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,21 +513,23 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY();
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||
string toSpeak = ___message;
|
||||
|
||||
MainClass.GetScreenReader().SayWithMenuChecker(___message, true);
|
||||
if (__instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker("Ok Button", false);
|
||||
toSpeak += "\n\tOk Button";
|
||||
}
|
||||
else if (__instance.cancelButton.containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker("Cancel Button", false);
|
||||
toSpeak += "\n\tCancel Button";
|
||||
}
|
||||
|
||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,13 +537,9 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY();
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||
string leftProfession = " ", rightProfession = " ", extraInfo = " ", newCraftingRecipe = " ", toSpeak = " ";
|
||||
|
||||
bool isOpenBracketPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.OemOpenBrackets); // for left click
|
||||
bool isLeftCtrlPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl);
|
||||
bool isEnterPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Enter);
|
||||
|
||||
if (!__instance.informationUp)
|
||||
{
|
||||
return;
|
||||
@@ -167,7 +561,7 @@ namespace stardew_access.Patches
|
||||
|
||||
if (__instance.leftProfession.containsPoint(x, y))
|
||||
{
|
||||
if (isOpenBracketPressed || (isLeftCtrlPressed && isEnterPressed && __instance.readyToClose()))
|
||||
if ((MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed()) && __instance.readyToClose())
|
||||
{
|
||||
Game1.player.professions.Add(___professionsToChoose[0]);
|
||||
__instance.getImmediateProfessionPerk(___professionsToChoose[0]);
|
||||
@@ -184,7 +578,7 @@ namespace stardew_access.Patches
|
||||
|
||||
if (__instance.rightProfession.containsPoint(x, y))
|
||||
{
|
||||
if (isOpenBracketPressed || (isLeftCtrlPressed && isEnterPressed && __instance.readyToClose()))
|
||||
if ((MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed()) && __instance.readyToClose())
|
||||
{
|
||||
Game1.player.professions.Add(___professionsToChoose[1]);
|
||||
__instance.getImmediateProfessionPerk(___professionsToChoose[1]);
|
||||
@@ -216,23 +610,23 @@ namespace stardew_access.Patches
|
||||
|
||||
if (__instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
if (isOpenBracketPressed || (isLeftCtrlPressed && isEnterPressed))
|
||||
if (MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed())
|
||||
__instance.okButtonClicked();
|
||||
|
||||
toSpeak = $"{___title} {extraInfo} {newCraftingRecipe}. Left click to close.";
|
||||
}
|
||||
|
||||
if (toSpeak != " ")
|
||||
MainClass.GetScreenReader().SayWithMenuChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||
else if (__instance.isProfessionChooser && currentLevelUpTitle != $"{___title}. Select a new profession.")
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker($"{___title}. Select a new profession.", true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker($"{___title}. Select a new profession.", true);
|
||||
currentLevelUpTitle = $"{___title}. Select a new profession.";
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,140 +634,47 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
bool isLeftControlPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftControl);
|
||||
bool isOpenBracketPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.OemOpenBrackets); // for left click
|
||||
bool isEnterPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Enter);
|
||||
|
||||
if (__instance.currentPage == -1)
|
||||
{
|
||||
int total = ___categoryTotals[5];
|
||||
string toSpeak;
|
||||
if (__instance.okButton.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.okButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
// Perform Left Click
|
||||
if (isOpenBracketPressed || (isLeftControlPressed && isEnterPressed))
|
||||
if (MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed())
|
||||
{
|
||||
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||
}
|
||||
toSpeak = $"{total}g in total. Press left mouse button to save.";
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
for (int i = 0; i < __instance.categories.Count; i++)
|
||||
{
|
||||
if (__instance.categories[i].containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.categories[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
toSpeak = $"Money recieved from {__instance.getCategoryName(i)}: {___categoryTotals[i]}g.";
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LetterViewerMenuPatch(LetterViewerMenu __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!__instance.IsActive())
|
||||
return;
|
||||
|
||||
#region Texts in the letter
|
||||
string message = __instance.mailMessage[__instance.page];
|
||||
|
||||
string toSpeak = $"{message}";
|
||||
|
||||
if (__instance.ShouldShowInteractable())
|
||||
{
|
||||
if (__instance.moneyIncluded > 0)
|
||||
{
|
||||
string moneyText = Game1.content.LoadString("Strings\\UI:LetterViewer_MoneyIncluded", __instance.moneyIncluded);
|
||||
toSpeak += $"\t\n\t ,Included money: {moneyText}";
|
||||
}
|
||||
else if (__instance.learnedRecipe != null && __instance.learnedRecipe.Length > 0)
|
||||
{
|
||||
string recipeText = Game1.content.LoadString("Strings\\UI:LetterViewer_LearnedRecipe", __instance.cookingOrCrafting);
|
||||
toSpeak += $"\t\n\t ,Learned Recipe: {recipeText}";
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLetterText != toSpeak)
|
||||
{
|
||||
currentLetterText = toSpeak;
|
||||
|
||||
// snap mouse to accept quest button
|
||||
if (__instance.acceptQuestButton != null && __instance.acceptQuestButton.visible)
|
||||
{
|
||||
toSpeak += "\t\n Left click to accept quest.";
|
||||
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
||||
}
|
||||
MainClass.GetScreenReader().Say(toSpeak, false);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Narrate items given in the mail
|
||||
if (__instance.ShouldShowInteractable())
|
||||
{
|
||||
foreach (ClickableComponent c in __instance.itemsToGrab)
|
||||
{
|
||||
string name = c.name;
|
||||
string label = c.label;
|
||||
|
||||
if (c.containsPoint(Game1.getMousePosition().X, Game1.getMousePosition().Y))
|
||||
MainClass.GetScreenReader().SayWithChecker($"Grab: {name} \t\n {label}", false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
#region Cleanup on exitting a menu
|
||||
internal static void Game1ExitActiveMenuPatch()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Game1.activeClickableMenu is GameMenu)
|
||||
{
|
||||
GameMenuPatches.gameMenuQueryKey = "";
|
||||
GameMenuPatches.craftingPageQueryKey = "";
|
||||
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 = "";
|
||||
Cleanup(Game1.activeClickableMenu);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,62 +682,120 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
if (__instance is GeodeMenu)
|
||||
{
|
||||
GameMenuPatches.geodeMenuQueryKey = "";
|
||||
}
|
||||
|
||||
if (__instance is ItemGrabMenu)
|
||||
{
|
||||
GameMenuPatches.itemGrabMenuQueryKey = "";
|
||||
}
|
||||
|
||||
if (__instance is ShopMenu)
|
||||
{
|
||||
GameMenuPatches.shopMenuQueryKey = "";
|
||||
}
|
||||
|
||||
if (__instance is CarpenterMenu)
|
||||
{
|
||||
BuildingNAnimalMenuPatches.carpenterMenuQuery = "";
|
||||
BuildingNAnimalMenuPatches.isUpgrading = false;
|
||||
BuildingNAnimalMenuPatches.isDemolishing = false;
|
||||
BuildingNAnimalMenuPatches.isPainting = false;
|
||||
BuildingNAnimalMenuPatches.isMoving = false;
|
||||
BuildingNAnimalMenuPatches.isConstructing = false;
|
||||
BuildingNAnimalMenuPatches.carpenterMenu = null;
|
||||
}
|
||||
|
||||
if (__instance is PurchaseAnimalsMenu)
|
||||
{
|
||||
BuildingNAnimalMenuPatches.purchaseAnimalMenuQuery = "";
|
||||
BuildingNAnimalMenuPatches.firstTimeInNamingMenu = true;
|
||||
BuildingNAnimalMenuPatches.purchaseAnimalsMenu = null;
|
||||
}
|
||||
|
||||
if (__instance is DialogueBox)
|
||||
{
|
||||
DialoguePatches.isDialogueAppearingFirstTime = true;
|
||||
DialoguePatches.currentDialogue = " ";
|
||||
}
|
||||
|
||||
GameMenuPatches.hoveredItemQueryKey = "";
|
||||
Cleanup(__instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void Cleanup(IClickableMenu menu)
|
||||
{
|
||||
if (menu is LetterViewerMenu)
|
||||
{
|
||||
DialoguePatches.currentLetterText = " ";
|
||||
}
|
||||
else if (menu is LevelUpMenu)
|
||||
{
|
||||
currentLevelUpTitle = " ";
|
||||
}
|
||||
else if (menu is Billboard)
|
||||
{
|
||||
QuestPatches.currentDailyQuestText = " ";
|
||||
}
|
||||
else if (menu is GameMenu)
|
||||
{
|
||||
GameMenuPatches.gameMenuQueryKey = "";
|
||||
GameMenuPatches.craftingPageQueryKey = "";
|
||||
GameMenuPatches.inventoryPageQueryKey = "";
|
||||
GameMenuPatches.exitPageQueryKey = "";
|
||||
GameMenuPatches.optionsPageQueryKey = "";
|
||||
GameMenuPatches.socialPageQuery = "";
|
||||
GameMenuPatches.currentSelectedCraftingRecipe = -1;
|
||||
GameMenuPatches.isSelectingRecipe = false;
|
||||
}
|
||||
else if (menu is JunimoNoteMenu)
|
||||
{
|
||||
BundleMenuPatches.currentIngredientListItem = -1;
|
||||
BundleMenuPatches.currentIngredientInputSlot = -1;
|
||||
BundleMenuPatches.currentInventorySlot = -1;
|
||||
BundleMenuPatches.junimoNoteMenuQuery = "";
|
||||
}
|
||||
else if (menu is ShopMenu)
|
||||
{
|
||||
GameMenuPatches.shopMenuQueryKey = "";
|
||||
}
|
||||
else if (menu is ItemGrabMenu)
|
||||
{
|
||||
GameMenuPatches.itemGrabMenuQueryKey = "";
|
||||
}
|
||||
else if (menu is GeodeMenu)
|
||||
{
|
||||
GameMenuPatches.geodeMenuQueryKey = "";
|
||||
}
|
||||
else if (menu is CarpenterMenu)
|
||||
{
|
||||
BuildingNAnimalMenuPatches.carpenterMenuQuery = "";
|
||||
BuildingNAnimalMenuPatches.isUpgrading = false;
|
||||
BuildingNAnimalMenuPatches.isDemolishing = false;
|
||||
BuildingNAnimalMenuPatches.isPainting = false;
|
||||
BuildingNAnimalMenuPatches.isMoving = false;
|
||||
BuildingNAnimalMenuPatches.isConstructing = false;
|
||||
BuildingNAnimalMenuPatches.carpenterMenu = null;
|
||||
}
|
||||
else if (menu is PurchaseAnimalsMenu)
|
||||
{
|
||||
BuildingNAnimalMenuPatches.purchaseAnimalMenuQuery = "";
|
||||
BuildingNAnimalMenuPatches.firstTimeInNamingMenu = true;
|
||||
BuildingNAnimalMenuPatches.purchaseAnimalsMenu = null;
|
||||
}
|
||||
else if (menu is DialogueBox)
|
||||
{
|
||||
DialoguePatches.isDialogueAppearingFirstTime = true;
|
||||
DialoguePatches.currentDialogue = " ";
|
||||
}
|
||||
else if (menu is JojaCDMenu)
|
||||
{
|
||||
BundleMenuPatches.jojaCDMenuQuery = "";
|
||||
}
|
||||
else if (menu is QuestLog)
|
||||
{
|
||||
QuestPatches.questLogQuery = " ";
|
||||
}
|
||||
else if (menu is TailoringMenu)
|
||||
{
|
||||
tailoringMenuQuery = " ";
|
||||
}
|
||||
else if (menu is ForgeMenu)
|
||||
{
|
||||
forgeMenuQuery = " ";
|
||||
}
|
||||
else if (menu is ItemListMenu)
|
||||
{
|
||||
itemListMenuQuery = " ";
|
||||
}
|
||||
else if (menu is FieldOfficeMenu)
|
||||
{
|
||||
DonationMenuPatches.fieldOfficeMenuQuery = " ";
|
||||
}
|
||||
else if (menu is MuseumMenu)
|
||||
{
|
||||
DonationMenuPatches.museumQueryKey = " ";
|
||||
}
|
||||
else if (menu is PondQueryMenu)
|
||||
{
|
||||
pondQueryMenuQuery = " ";
|
||||
}
|
||||
|
||||
GameMenuPatches.hoveredItemQueryKey = "";
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static void ExitEventPatch()
|
||||
{
|
||||
if (MainClass.GetScreenReader() != null)
|
||||
MainClass.GetScreenReader().CloseScreenReader();
|
||||
}
|
||||
internal static void resetGlobalVars()
|
||||
{
|
||||
currentLetterText = " ";
|
||||
currentLevelUpTitle = " ";
|
||||
if (MainClass.ScreenReader != null)
|
||||
MainClass.ScreenReader.CloseScreenReader();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
120
stardew-access/Patches/MiniGamesPatches.cs
Normal file
120
stardew-access/Patches/MiniGamesPatches.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewValley;
|
||||
using StardewValley.Minigames;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
{
|
||||
public class MiniGamesPatches
|
||||
{
|
||||
public static string grandpaStoryQuery = " ";
|
||||
public static string introQuery = " ";
|
||||
|
||||
internal static void IntroPatch(Intro __instance, int ___currentState)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
string toSpeak = " ";
|
||||
|
||||
if (___currentState == 3)
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("intro.scene3");
|
||||
}
|
||||
else if (___currentState == 4)
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("intro.scene4");
|
||||
}
|
||||
|
||||
if (toSpeak != " " && introQuery != toSpeak)
|
||||
{
|
||||
introQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void GrandpaStoryPatch(GrandpaStory __instance, StardewValley.Menus.LetterViewerMenu ___letterView, bool ___drawGrandpa, bool ___letterReceived, bool ___mouseActive, Queue<string> ___grandpaSpeech, int ___grandpaSpeechTimer, int ___totalMilliseconds, int ___scene, int ___parallaxPan)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = " ";
|
||||
|
||||
if (___letterView != null)
|
||||
{
|
||||
DialoguePatches.NarrateLetterContent(___letterView);
|
||||
}
|
||||
|
||||
if (MainClass.ModHelper == null)
|
||||
return;
|
||||
|
||||
if (___scene == 0)
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("grandpastory.scene0");
|
||||
}
|
||||
else if (___drawGrandpa)
|
||||
{
|
||||
if (___grandpaSpeech.Count > 0 && ___grandpaSpeechTimer > 3000)
|
||||
{
|
||||
toSpeak = ___grandpaSpeech.Peek();
|
||||
}
|
||||
}
|
||||
else if (___scene == 3)
|
||||
{
|
||||
toSpeak = Game1.content.LoadString("Strings\\StringsFromCSFiles:GrandpaStory.cs.12059");
|
||||
}
|
||||
else if (___scene == 4)
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("grandpastory.scene4");
|
||||
}
|
||||
else if (___scene == 5)
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("grandpastory.scene5");
|
||||
}
|
||||
else if (___scene == 6)
|
||||
{
|
||||
if (___grandpaSpeechTimer > 3000)
|
||||
{
|
||||
if (clickableGrandpaLetterRect(___parallaxPan, ___grandpaSpeechTimer).Contains(x, y))
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("grandpastory.letteropen");
|
||||
}
|
||||
else if (___letterView == null)
|
||||
{
|
||||
Point pos = clickableGrandpaLetterRect(___parallaxPan, ___grandpaSpeechTimer).Center;
|
||||
Game1.setMousePositionRaw((int)((float)pos.X * Game1.options.zoomLevel), (int)((float)pos.Y * Game1.options.zoomLevel));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
toSpeak = MainClass.ModHelper.Translation.Get("grandpastory.scene6");
|
||||
}
|
||||
}
|
||||
|
||||
if (toSpeak != " " && grandpaStoryQuery != toSpeak)
|
||||
{
|
||||
grandpaStoryQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, false);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
// This method is taken from the game's source code
|
||||
private static Rectangle clickableGrandpaLetterRect(int ___parallaxPan, int ___grandpaSpeechTimer)
|
||||
{
|
||||
return new Rectangle((int)Utility.getTopLeftPositionForCenteringOnScreen(Game1.viewport, 1294, 730).X + (286 - ___parallaxPan) * 4, (int)Utility.getTopLeftPositionForCenteringOnScreen(Game1.viewport, 1294, 730).Y + 218 + Math.Max(0, Math.Min(60, (___grandpaSpeechTimer - 5000) / 8)), 524, 344);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley.Menus;
|
||||
using StardewValley.Quests;
|
||||
@@ -8,14 +7,16 @@ namespace stardew_access.Patches
|
||||
{
|
||||
internal class QuestPatches
|
||||
{
|
||||
private static string currentDailyQuestText = " ";
|
||||
internal static string currentDailyQuestText = " ";
|
||||
internal static string questLogQuery = " ";
|
||||
internal static bool isNarratingQuestInfo = false, firstTimeInIndividualQuest = true;
|
||||
|
||||
#region For Special Orders Board
|
||||
internal static void SpecialOrdersBoardPatch(SpecialOrdersBoard __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY(); // Mouse x and y position
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
|
||||
if (__instance.acceptLeftQuestButton.visible && __instance.acceptLeftQuestButton.containsPoint(x, y))
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace stardew_access.Patches
|
||||
|
||||
toSpeak = $"Left Quest:\n\t{toSpeak}\n\tPress left click to accept this quest.";
|
||||
|
||||
MainClass.GetScreenReader().SayWithMenuChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,13 +34,13 @@ namespace stardew_access.Patches
|
||||
|
||||
toSpeak = $"Right Quest:\n\t{toSpeak}\n\tPress left click to accept this quest.";
|
||||
|
||||
MainClass.GetScreenReader().SayWithMenuChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace stardew_access.Patches
|
||||
#region Callender
|
||||
for (int i = 0; i < __instance.calendarDays.Count; i++)
|
||||
{
|
||||
if (__instance.calendarDays[i].containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.calendarDays[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
string toSpeak = $"Day {i + 1}";
|
||||
|
||||
@@ -99,7 +100,7 @@ namespace stardew_access.Patches
|
||||
if (Game1.dayOfMonth == i + 1)
|
||||
toSpeak += $", Current";
|
||||
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -114,7 +115,7 @@ namespace stardew_access.Patches
|
||||
if (currentDailyQuestText != toSpeak)
|
||||
{
|
||||
currentDailyQuestText = toSpeak;
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -134,7 +135,7 @@ namespace stardew_access.Patches
|
||||
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
||||
}
|
||||
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -142,7 +143,7 @@ namespace stardew_access.Patches
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -152,101 +153,135 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
bool snapMouseToRewardBox = false;
|
||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||
string toSpeak = " ", extra = "";
|
||||
|
||||
if (___questPage == -1)
|
||||
{
|
||||
#region Quest Lists
|
||||
if (!firstTimeInIndividualQuest)
|
||||
firstTimeInIndividualQuest = true;
|
||||
|
||||
for (int i = 0; i < __instance.questLogButtons.Count; i++)
|
||||
{
|
||||
if (___pages.Count() > 0 && ___pages[___currentPage].Count() > i)
|
||||
{
|
||||
if (!__instance.questLogButtons[i].containsPoint(x, y))
|
||||
continue;
|
||||
|
||||
string name = ___pages[___currentPage][i].GetName();
|
||||
int daysLeft = ___pages[___currentPage][i].GetDaysLeft();
|
||||
string toSpeak = $"{name} quest";
|
||||
toSpeak = $"{name}";
|
||||
|
||||
if (daysLeft > 0 && ___pages[___currentPage][i].ShouldDisplayAsComplete())
|
||||
toSpeak += $"\t\n {daysLeft} days left";
|
||||
|
||||
toSpeak += ___pages[___currentPage][i].ShouldDisplayAsComplete() ? " completed!" : "";
|
||||
if (__instance.questLogButtons[i].containsPoint(Game1.getOldMouseX(), Game1.getOldMouseY()))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
||||
toSpeak = "Previous page button";
|
||||
else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
||||
toSpeak = "Next page button";
|
||||
else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y))
|
||||
toSpeak = "Close menu button";
|
||||
|
||||
if (questLogQuery != toSpeak)
|
||||
{
|
||||
questLogQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Individual quest
|
||||
bool containsReward = __instance.HasReward() || __instance.HasMoneyReward();
|
||||
string description = Game1.parseText(____shownQuest.GetDescription(), Game1.dialogueFont, __instance.width - 128);
|
||||
string title = ____shownQuest.GetName();
|
||||
string toSpeak = " ";
|
||||
if (____shownQuest.ShouldDisplayAsComplete())
|
||||
|
||||
if (firstTimeInIndividualQuest || (isPrimaryInfoKeyPressed && !isNarratingQuestInfo))
|
||||
{
|
||||
#region Quest completed menu
|
||||
if (firstTimeInIndividualQuest)
|
||||
toSpeak = "Back button";
|
||||
|
||||
toSpeak = $"Quest: {title} Completed!";
|
||||
|
||||
if (__instance.HasReward())
|
||||
if (____shownQuest.ShouldDisplayAsComplete())
|
||||
{
|
||||
snapMouseToRewardBox = true;
|
||||
#region Quest completed menu
|
||||
|
||||
extra = $"Quest: {title} Completed!";
|
||||
|
||||
if (__instance.HasMoneyReward())
|
||||
extra += $"you recieved {____shownQuest.GetMoneyReward()}g";
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Quest in-complete menu
|
||||
extra = $"Title: {title}. \t\n Description: {description}";
|
||||
|
||||
for (int j = 0; j < ____objectiveText.Count; j++)
|
||||
{
|
||||
toSpeak += $"you recieved {____shownQuest.GetMoneyReward()}g";
|
||||
string parsed_text = Game1.parseText(____objectiveText[j], width: __instance.width - 192, whichFont: Game1.dialogueFont);
|
||||
if (____shownQuest != null && ____shownQuest is SpecialOrder)
|
||||
{
|
||||
OrderObjective order_objective = ((SpecialOrder)____shownQuest).objectives[j];
|
||||
if (order_objective.GetMaxCount() > 1 && order_objective.ShouldShowProgress())
|
||||
parsed_text += "\n\t" + order_objective.GetCount() + " of " + order_objective.GetMaxCount() + " completed";
|
||||
}
|
||||
|
||||
extra += $"\t\nOrder {j + 1}: {parsed_text} \t\n";
|
||||
}
|
||||
|
||||
toSpeak += "... left click to collect reward";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Quest in-complete menu
|
||||
toSpeak = $"Title: {title}. \t\n Description: {description}";
|
||||
|
||||
for (int j = 0; j < ____objectiveText.Count; j++)
|
||||
{
|
||||
if (____shownQuest != null)
|
||||
{
|
||||
_ = ____shownQuest is SpecialOrder;
|
||||
int daysLeft = ____shownQuest.GetDaysLeft();
|
||||
|
||||
if (daysLeft > 0)
|
||||
extra += $"\t\n{daysLeft} days left.";
|
||||
}
|
||||
string parsed_text = Game1.parseText(____objectiveText[j], width: __instance.width - 192, whichFont: Game1.dialogueFont);
|
||||
|
||||
toSpeak += $"\t\nOrder {j + 1}: {parsed_text} \t\n";
|
||||
#endregion
|
||||
}
|
||||
|
||||
if (____shownQuest != null)
|
||||
{
|
||||
int daysLeft = ____shownQuest.GetDaysLeft();
|
||||
|
||||
if (daysLeft > 0)
|
||||
toSpeak += $"\t\n{daysLeft} days left.";
|
||||
}
|
||||
#endregion
|
||||
isNarratingQuestInfo = true;
|
||||
Task.Delay(200).ContinueWith(_ => { isNarratingQuestInfo = false; });
|
||||
questLogQuery = " ";
|
||||
}
|
||||
|
||||
// Move mouse to reward button
|
||||
if (snapMouseToRewardBox)
|
||||
__instance.rewardBox.snapMouseCursorToCenter();
|
||||
if (!firstTimeInIndividualQuest)
|
||||
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
||||
toSpeak = (___currentPage > 0) ? "Previous page button" : "Back button";
|
||||
else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
||||
toSpeak = "Next page button";
|
||||
else if (__instance.cancelQuestButton != null && __instance.cancelQuestButton.visible && __instance.cancelQuestButton.containsPoint(x, y))
|
||||
toSpeak = "Cancel quest button";
|
||||
else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y))
|
||||
toSpeak = "Close menu button";
|
||||
else if (containsReward && __instance.rewardBox.containsPoint(x, y))
|
||||
toSpeak = "Left click to collect reward";
|
||||
|
||||
if (firstTimeInIndividualQuest || (questLogQuery != toSpeak))
|
||||
{
|
||||
questLogQuery = toSpeak;
|
||||
MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true);
|
||||
|
||||
if (firstTimeInIndividualQuest)
|
||||
firstTimeInIndividualQuest = false;
|
||||
}
|
||||
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
internal static void resetGlobalVars()
|
||||
{
|
||||
currentDailyQuestText = " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using StardewValley;
|
||||
using StardewValley.Characters;
|
||||
using StardewValley.Menus;
|
||||
using static StardewValley.Menus.CharacterCustomization;
|
||||
using static StardewValley.Menus.LoadGameMenu;
|
||||
|
||||
namespace stardew_access.Patches
|
||||
@@ -10,13 +10,83 @@ namespace stardew_access.Patches
|
||||
{
|
||||
private static int saveGameIndex = -1;
|
||||
private static bool isRunning = false;
|
||||
private const int MAX_COMPONENTS = 20;
|
||||
public static string characterCreationMenuQueryKey = " ";
|
||||
public static string advancedGameOptionsQueryKey = " ";
|
||||
public static string prevPetName = " ";
|
||||
|
||||
internal static void AdvancedGameOptionsPatch(AdvancedGameOptions __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
int currentItemIndex = Math.Max(0, Math.Min(__instance.options.Count - 7, __instance.currentItemIndex));
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||
|
||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||
{
|
||||
string toSpeak = "OK Button";
|
||||
if (advancedGameOptionsQueryKey != toSpeak)
|
||||
{
|
||||
advancedGameOptionsQueryKey = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < __instance.optionSlots.Count; i++)
|
||||
{
|
||||
if (__instance.optionSlots[i].bounds.Contains(x, y) && currentItemIndex + i < __instance.options.Count && __instance.options[currentItemIndex + i].bounds.Contains(x - __instance.optionSlots[i].bounds.X, y - __instance.optionSlots[i].bounds.Y))
|
||||
{
|
||||
OptionsElement optionsElement = __instance.options[currentItemIndex + i];
|
||||
string toSpeak = optionsElement.label;
|
||||
|
||||
if (optionsElement is OptionsButton)
|
||||
toSpeak = $" {toSpeak} Button";
|
||||
else if (optionsElement is OptionsCheckbox)
|
||||
toSpeak = (((OptionsCheckbox)optionsElement).isChecked ? "Enabled" : "Disabled") + $" {toSpeak} Checkbox";
|
||||
else if (optionsElement is OptionsDropDown)
|
||||
toSpeak = $"{toSpeak} Dropdown, option {((OptionsDropDown)optionsElement).dropDownDisplayOptions[((OptionsDropDown)optionsElement).selectedOption]} selected";
|
||||
else if (optionsElement is OptionsSlider)
|
||||
toSpeak = $"{((OptionsSlider)optionsElement).value}% {toSpeak} Slider";
|
||||
else if (optionsElement is OptionsPlusMinus)
|
||||
toSpeak = $"{((OptionsPlusMinus)optionsElement).displayOptions[((OptionsPlusMinus)optionsElement).selected]} selected of {toSpeak}";
|
||||
else if (optionsElement is OptionsInputListener)
|
||||
{
|
||||
string buttons = "";
|
||||
((OptionsInputListener)optionsElement).buttonNames.ForEach(name => { buttons += $", {name}"; });
|
||||
toSpeak = $"{toSpeak} is bound to {buttons}. Left click to change.";
|
||||
}
|
||||
else if (optionsElement is OptionsTextEntry)
|
||||
{
|
||||
toSpeak = $"Seed text box";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (toSpeak.Contains(":"))
|
||||
toSpeak = toSpeak.Replace(":", "");
|
||||
|
||||
toSpeak = $"{toSpeak} Options:";
|
||||
}
|
||||
|
||||
if (advancedGameOptionsQueryKey != toSpeak)
|
||||
{
|
||||
advancedGameOptionsQueryKey = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void CoopMenuPatch(CoopMenu __instance, CoopMenu.Tab ___currentTab)
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY();
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||
string toSpeak = " ";
|
||||
|
||||
#region Join/Host Button (Important! This should be checked before checking other buttons)
|
||||
@@ -45,11 +115,11 @@ namespace stardew_access.Patches
|
||||
#endregion
|
||||
|
||||
if (toSpeak != " ")
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +134,7 @@ namespace stardew_access.Patches
|
||||
|
||||
__instance.buttons.ForEach(component =>
|
||||
{
|
||||
if (component.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (component.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
string name = component.name;
|
||||
string label = component.label;
|
||||
@@ -72,38 +142,48 @@ namespace stardew_access.Patches
|
||||
}
|
||||
});
|
||||
|
||||
if (__instance.muteMusicButton.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.muteMusicButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
toSpeak = "Mute Music Button";
|
||||
}
|
||||
|
||||
if (__instance.aboutButton.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.aboutButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
toSpeak = "About Button";
|
||||
}
|
||||
|
||||
if (__instance.languageButton.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.languageButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
toSpeak = "Language Button";
|
||||
}
|
||||
|
||||
if (__instance.windowedButton.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (__instance.windowedButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
toSpeak = "Fullscreen toggle Button";
|
||||
toSpeak = "Fullscreen: " + ((Game1.isFullscreen) ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
if (TitleMenu.subMenu != null && __instance.backButton.containsPoint(Game1.getMouseX(), Game1.getMouseY()))
|
||||
if (TitleMenu.subMenu != null && __instance.backButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
string text = "Back Button";
|
||||
MainClass.GetScreenReader().SayWithChecker(text, true);
|
||||
MainClass.ScreenReader.SayWithChecker(text, true);
|
||||
}
|
||||
|
||||
// Fix for back button not working using keyboard
|
||||
if (TitleMenu.subMenu is CharacterCustomization && ((CharacterCustomization)TitleMenu.subMenu).backButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||
{
|
||||
// Perform Left Click
|
||||
if (MainClass.Config.LeftClickMainKey.JustPressed())
|
||||
{
|
||||
__instance.backButtonPressed();
|
||||
}
|
||||
}
|
||||
|
||||
if (TitleMenu.subMenu == null && toSpeak != "")
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +191,7 @@ namespace stardew_access.Patches
|
||||
{
|
||||
try
|
||||
{
|
||||
int x = Game1.getMouseX(), y = Game1.getMouseY();
|
||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||
if (___menu.slotButtons[i].containsPoint(x, y))
|
||||
{
|
||||
if (__instance.Farmer != null)
|
||||
@@ -119,7 +199,7 @@ namespace stardew_access.Patches
|
||||
#region Farms
|
||||
if (___menu.deleteButtons.Count > 0 && ___menu.deleteButtons[i].containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithChecker($"Delete {__instance.Farmer.farmName} Farm", true);
|
||||
MainClass.ScreenReader.SayWithChecker($"Delete {__instance.Farmer.farmName.Value} Farm", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,523 +208,230 @@ namespace stardew_access.Patches
|
||||
// Used diff. functions to narrate to prevent it from speaking the message again on selecting another button.
|
||||
string message = "Really delete farm?";
|
||||
|
||||
MainClass.GetScreenReader().SayWithChecker(message, true);
|
||||
MainClass.ScreenReader.SayWithChecker(message, true);
|
||||
if (___menu.okDeleteButton.containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker("Ok Button", false);
|
||||
MainClass.ScreenReader.SayWithMenuChecker("Ok Button", false);
|
||||
}
|
||||
else if (___menu.cancelDeleteButton.containsPoint(x, y))
|
||||
{
|
||||
MainClass.GetScreenReader().SayWithMenuChecker("Cancel Button", false);
|
||||
MainClass.ScreenReader.SayWithMenuChecker("Cancel Button", false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String farmerName = __instance.Farmer.displayName;
|
||||
String farmName = __instance.Farmer.farmName;
|
||||
String farmName = __instance.Farmer.farmName.Value;
|
||||
String money = __instance.Farmer.Money.ToString();
|
||||
String hoursPlayed = Utility.getHoursMinutesStringFromMilliseconds(__instance.Farmer.millisecondsPlayed);
|
||||
string dateStringForSaveGame = ((!__instance.Farmer.dayOfMonthForSaveGame.HasValue ||
|
||||
!__instance.Farmer.seasonForSaveGame.HasValue ||
|
||||
!__instance.Farmer.yearForSaveGame.HasValue) ? __instance.Farmer.dateStringForSaveGame : Utility.getDateStringFor(__instance.Farmer.dayOfMonthForSaveGame.Value, __instance.Farmer.seasonForSaveGame.Value, __instance.Farmer.yearForSaveGame.Value));
|
||||
|
||||
string toSpeak = $"{farmName} Farm Selected, \t\n Farmer:{farmerName}, \t\nMoney:{money}, \t\nHours Played:{hoursPlayed}, \t\nDate:{dateStringForSaveGame}";
|
||||
string toSpeak = $"{farmName} Farm Selected, \t\n Farmer: {farmerName}, \t\nMoney: {money}, \t\nHours Played: {hoursPlayed}, \t\nDate: {dateStringForSaveGame}";
|
||||
|
||||
MainClass.GetScreenReader().SayWithChecker(toSpeak, true);
|
||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void NewGameMenuPatch(CharacterCustomization __instance, bool ___skipIntro)
|
||||
internal static void CharacterCustomizationMenuPatch(CharacterCustomization __instance, bool ___skipIntro,
|
||||
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
|
||||
TextBox ___farmnameBox, TextBox ___favThingBox)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool isNextArrowPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Right);
|
||||
bool isPrevArrowPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Left);
|
||||
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
||||
string toSpeak = " ";
|
||||
string currentPetName = getCurrentPetName();
|
||||
|
||||
if (isNextArrowPressed && !isRunning)
|
||||
if (___nameBox.Selected)
|
||||
{
|
||||
_ = CycleThroughItems(true, __instance, ___skipIntro);
|
||||
toSpeak = ___nameBox.Text;
|
||||
|
||||
if (isEscPressed)
|
||||
{
|
||||
___nameBox.Selected = false;
|
||||
}
|
||||
}
|
||||
else if (isPrevArrowPressed && !isRunning)
|
||||
else if (___farmnameBox.Selected)
|
||||
{
|
||||
_ = CycleThroughItems(false, __instance, ___skipIntro);
|
||||
toSpeak = ___farmnameBox.Text;
|
||||
|
||||
if (isEscPressed)
|
||||
{
|
||||
___farmnameBox.Selected = false;
|
||||
}
|
||||
}
|
||||
else if (___favThingBox.Selected)
|
||||
{
|
||||
toSpeak = ___favThingBox.Text;
|
||||
|
||||
if (isEscPressed)
|
||||
{
|
||||
___favThingBox.Selected = false;
|
||||
}
|
||||
}
|
||||
else if (MainClass.Config.CharacterCreationMenuNextKey.JustPressed() && !isRunning)
|
||||
{
|
||||
isRunning = true;
|
||||
CycleThroughItems(true, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel);
|
||||
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
|
||||
}
|
||||
else if (MainClass.Config.CharacterCreationMenuPreviousKey.JustPressed() && !isRunning)
|
||||
{
|
||||
isRunning = true;
|
||||
CycleThroughItems(false, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel);
|
||||
Task.Delay(200).ContinueWith(_ => { isRunning = false; });
|
||||
}
|
||||
|
||||
if (prevPetName != currentPetName)
|
||||
{
|
||||
prevPetName = currentPetName;
|
||||
toSpeak = $"Current Pet: {currentPetName} \n {toSpeak}";
|
||||
}
|
||||
|
||||
if (characterCreationMenuQueryKey != toSpeak && toSpeak != " ")
|
||||
{
|
||||
characterCreationMenuQueryKey = toSpeak;
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainClass.GetMonitor().Log($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}", LogLevel.Error);
|
||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro)
|
||||
private static void CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro,
|
||||
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel)
|
||||
{
|
||||
isRunning = true;
|
||||
string toSpeak = " ";
|
||||
Dictionary<ClickableComponent, string> buttons = new();
|
||||
|
||||
#region Add buttons with their names IF they are available
|
||||
|
||||
#region Character related
|
||||
if (__instance.nameBoxCC != null && __instance.nameBoxCC.visible)
|
||||
buttons.Add(__instance.nameBoxCC, "Farmer's Name Text box");
|
||||
|
||||
if (__instance.farmnameBoxCC != null && __instance.farmnameBoxCC.visible)
|
||||
buttons.Add(__instance.farmnameBoxCC, "Farm's Name Text box");
|
||||
|
||||
if (__instance.favThingBoxCC != null && __instance.favThingBoxCC.visible)
|
||||
buttons.Add(__instance.favThingBoxCC, "Favourite Thing Text box");
|
||||
|
||||
if (__instance.petPortraitBox.HasValue) // Cannot get petButtons like with others
|
||||
{
|
||||
ClickableComponent petPrev = __instance.getComponentWithID(511);
|
||||
buttons.Add(petPrev, "Previous pet button");
|
||||
|
||||
ClickableComponent petNext = __instance.getComponentWithID(510);
|
||||
buttons.Add(petNext, "Next pet button");
|
||||
}
|
||||
|
||||
if (__instance.randomButton != null && __instance.randomButton.visible)
|
||||
buttons.Add(__instance.randomButton, "Random Skin Button");
|
||||
|
||||
if (__instance.genderButtons.Count > 0)
|
||||
{
|
||||
buttons.Add(__instance.genderButtons[0], ((Game1.player.IsMale) ? "Selected " : "") + "Gender: Male Button");
|
||||
buttons.Add(__instance.genderButtons[1], ((!Game1.player.IsMale) ? "Selected " : "") + "Gender: Female Button");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Farm layout related
|
||||
if (__instance.farmTypeButtons.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < __instance.farmTypeButtons.Count; i++)
|
||||
{
|
||||
buttons.Add(__instance.farmTypeButtons[i], ((i == Game1.whichFarm) ? "Selected " : "") + getFarmHoverText(__instance.farmTypeButtons[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (__instance.farmTypeNextPageButton != null && __instance.farmTypeNextPageButton.visible)
|
||||
buttons.Add(__instance.farmTypeNextPageButton, "Next Farm Type Page Button");
|
||||
|
||||
if (__instance.farmTypePreviousPageButton != null && __instance.farmTypePreviousPageButton.visible)
|
||||
buttons.Add(__instance.farmTypePreviousPageButton, "Previous Farm Type Page Button");
|
||||
#endregion
|
||||
|
||||
#region Co-op related
|
||||
if (__instance.source == Source.HostNewFarm)
|
||||
{
|
||||
ClickableComponent cabinLeft = __instance.getComponentWithID(621);
|
||||
if (Game1.startingCabins > 0)
|
||||
buttons.Add(cabinLeft, "Decrease starting cabins button");
|
||||
|
||||
buttons.Add(___startingCabinsLabel, $"Starting cabins: {Game1.startingCabins}");
|
||||
|
||||
ClickableComponent cabinRight = __instance.getComponentWithID(622);
|
||||
if (Game1.startingCabins < 3)
|
||||
buttons.Add(cabinRight, "Increase starting cabins button");
|
||||
|
||||
if (Game1.startingCabins > 0)
|
||||
{
|
||||
buttons.Add(__instance.cabinLayoutButtons[0], "Cabin layout to nearby Button");
|
||||
buttons.Add(__instance.cabinLayoutButtons[1], "Cabin layout to separate Button");
|
||||
}
|
||||
|
||||
ClickableComponent difficultyLeft = __instance.getComponentWithID(627);
|
||||
buttons.Add(difficultyLeft, "Increase profit margin button");
|
||||
buttons.Add(___difficultyModifierLabel, "Profit Margin: " + (((Game1.player.difficultyModifier * 100) == 100f) ? "normal" : Game1.player.difficultyModifier.ToString()));
|
||||
ClickableComponent difficultyRight = __instance.getComponentWithID(628);
|
||||
buttons.Add(difficultyRight, "Decrease profit margin button");
|
||||
|
||||
ClickableComponent walletLeft = __instance.getComponentWithID(631);
|
||||
buttons.Add(walletLeft, "Money style to " + ((!Game1.player.team.useSeparateWallets.Value) ? "separate wallets" : "shared wallets") + " button");
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (__instance.skipIntroButton != null && __instance.skipIntroButton.visible)
|
||||
buttons.Add(__instance.skipIntroButton, (___skipIntro ? "Enabled" : "Disabled") + " Skip Intro Button");
|
||||
|
||||
if (__instance.advancedOptionsButton != null && __instance.advancedOptionsButton.visible)
|
||||
buttons.Add(__instance.advancedOptionsButton, "Advanced Options Button");
|
||||
|
||||
if (__instance.okButton != null && __instance.okButton.visible)
|
||||
buttons.Add(__instance.okButton, "OK Button");
|
||||
|
||||
if (__instance.backButton != null && __instance.backButton.visible)
|
||||
buttons.Add(__instance.backButton, "Back Button");
|
||||
#endregion
|
||||
|
||||
int size = buttons.Count - 1;
|
||||
|
||||
if (increase)
|
||||
{
|
||||
saveGameIndex++;
|
||||
if (saveGameIndex > MAX_COMPONENTS)
|
||||
saveGameIndex = 1;
|
||||
if (saveGameIndex > size)
|
||||
saveGameIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveGameIndex--;
|
||||
if (saveGameIndex < 1)
|
||||
saveGameIndex = MAX_COMPONENTS;
|
||||
if (saveGameIndex < 0)
|
||||
saveGameIndex = size;
|
||||
}
|
||||
|
||||
|
||||
switch (saveGameIndex)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (!__instance.nameBoxCC.visible)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case MAX_COMPONENTS;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.nameBoxCC.snapMouseCursorToCenter();
|
||||
toSpeak = "Enter Farmer's Name";
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (!__instance.farmnameBoxCC.visible)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 1;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmnameBoxCC.snapMouseCursorToCenter();
|
||||
toSpeak = "Enter Farm's Name";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (!__instance.favThingBoxCC.visible)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.favThingBoxCC.snapMouseCursorToCenter();
|
||||
toSpeak = "Enter Favourite Thing";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (!__instance.skipIntroButton.visible)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 3;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.skipIntroButton.snapMouseCursor();
|
||||
toSpeak = (___skipIntro ? "Enabled" : "Disabled") + " Skip Intro Button";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (!__instance.randomButton.visible)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 5;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.randomButton.snapMouseCursor();
|
||||
toSpeak = "Random Skin Button";
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.genderButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 6;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.genderButtons[0].snapMouseCursor();
|
||||
toSpeak = "Gender Male Button";
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.genderButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 6;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.genderButtons[1].snapMouseCursor();
|
||||
toSpeak = "Gender Female Button";
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 7;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[0].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[0]);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 8;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[1].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[1]);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 11;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 9;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[2].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[2]);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 10;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[3].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[3]);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 13;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 11;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[4].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[4]);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 12;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[5].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[5]);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 13;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeButtons[6].snapMouseCursor();
|
||||
toSpeak = getFarmHoverText(__instance.farmTypeButtons[6]);
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypeNextPageButton == null)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 14;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypeNextPageButton.snapMouseCursor();
|
||||
toSpeak = "Next Farm Type Page Button";
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.farmTypePreviousPageButton == null)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 17;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 15;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.farmTypePreviousPageButton.snapMouseCursor();
|
||||
toSpeak = "Previous Farm Type Page Button";
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.cabinLayoutButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 16;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.cabinLayoutButtons[0].snapMouseCursor();
|
||||
toSpeak = "Cabin layout nearby";
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (__instance.cabinLayoutButtons.Count <= 0)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 19;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 17;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.cabinLayoutButtons[1].snapMouseCursor();
|
||||
toSpeak = "Cabin layout separate";
|
||||
break;
|
||||
}
|
||||
case 19:
|
||||
{
|
||||
#region Skip if button is not available
|
||||
if (!__instance.okButton.visible)
|
||||
{
|
||||
if (increase)
|
||||
{
|
||||
++saveGameIndex;
|
||||
goto case 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
--saveGameIndex;
|
||||
goto case 20;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.okButton.snapMouseCursor();
|
||||
toSpeak = "Ok Button";
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
{
|
||||
#region Exit if button is not available
|
||||
if (!__instance.backButton.visible)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
|
||||
__instance.backButton.snapMouseCursor();
|
||||
toSpeak = "Back Button";
|
||||
}
|
||||
break;
|
||||
}
|
||||
buttons.ElementAt(saveGameIndex).Key.snapMouseCursor();
|
||||
toSpeak = buttons.ElementAt(saveGameIndex).Value;
|
||||
|
||||
if (toSpeak != " ")
|
||||
{
|
||||
MainClass.GetScreenReader().Say(toSpeak, true);
|
||||
MainClass.ScreenReader.Say(toSpeak, true);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(200);
|
||||
isRunning = false;
|
||||
private static string getCurrentPetName()
|
||||
{
|
||||
return ((Game1.player.catPerson) ? "Cat" : "Dog") + " Breed: " + Game1.player.whichPetBreed;
|
||||
}
|
||||
|
||||
private static string getFarmHoverText(ClickableTextureComponent farm)
|
||||
|
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
Linux speech dispatcher library used:
|
||||
https://github.com/shoaib11120/libspeechdwrapper
|
||||
*/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace stardew_access.ScreenReader
|
||||
@@ -36,10 +41,16 @@ namespace stardew_access.ScreenReader
|
||||
|
||||
public void InitializeScreenReader()
|
||||
{
|
||||
MainClass.InfoLog("Initializing speech dispatcher...");
|
||||
int res = Initialize();
|
||||
if (res == 1)
|
||||
{
|
||||
initialized = true;
|
||||
MainClass.InfoLog("Successfully initialized.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.ErrorLog("Unable to initialize.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,10 +68,24 @@ namespace stardew_access.ScreenReader
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
if (initialized)
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
if (!MainClass.Config.TTS)
|
||||
return;
|
||||
|
||||
if (text.Contains('^')) text = text.Replace('^', '\n');
|
||||
|
||||
GoString str = new GoString(text, text.Length);
|
||||
int re = Speak(str, interrupt);
|
||||
|
||||
if (re == 1)
|
||||
{
|
||||
GoString str = new GoString(text, text.Length);
|
||||
Speak(str, interrupt);
|
||||
MainClass.DebugLog($"Speaking(interrupt: {interrupt}) = {text}");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.ErrorLog($"Failed to output text: {text}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
using AccessibleOutput;
|
||||
using DavyKager;
|
||||
|
||||
namespace stardew_access.ScreenReader
|
||||
{
|
||||
public class ScreenReaderWindows : IScreenReader
|
||||
{
|
||||
public IAccessibleOutput? screenReader = null;
|
||||
private bool isLoaded = false;
|
||||
public string prevText = "", prevTextTile = " ", prevChatText = "", prevMenuText = "";
|
||||
|
||||
public string PrevTextTile
|
||||
@@ -15,43 +15,31 @@ namespace stardew_access.ScreenReader
|
||||
|
||||
public void InitializeScreenReader()
|
||||
{
|
||||
MainClass.InfoLog("Initializing Tolk...");
|
||||
Tolk.TrySAPI(true);
|
||||
Tolk.Load();
|
||||
|
||||
NvdaOutput? nvdaOutput = null;
|
||||
JawsOutput? jawsOutput = null;
|
||||
SapiOutput? sapiOutput = null;
|
||||
|
||||
// Initialize NVDA
|
||||
try
|
||||
MainClass.InfoLog("Querying for the active screen reader driver...");
|
||||
string name = Tolk.DetectScreenReader();
|
||||
if (name != null)
|
||||
{
|
||||
nvdaOutput = new NvdaOutput();
|
||||
MainClass.InfoLog($"The active screen reader driver is: {name}");
|
||||
isLoaded = true;
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
// Initialize JAWS
|
||||
try
|
||||
else
|
||||
{
|
||||
jawsOutput = new JawsOutput();
|
||||
MainClass.ErrorLog("None of the supported screen readers is running");
|
||||
isLoaded = false;
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
// Initialize SAPI
|
||||
try
|
||||
{
|
||||
sapiOutput = new SapiOutput();
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
if (nvdaOutput != null && nvdaOutput.IsAvailable())
|
||||
screenReader = nvdaOutput;
|
||||
else if (jawsOutput != null && jawsOutput.IsAvailable())
|
||||
screenReader = jawsOutput;
|
||||
else if (sapiOutput != null && sapiOutput.IsAvailable())
|
||||
screenReader = sapiOutput;
|
||||
}
|
||||
|
||||
public void CloseScreenReader()
|
||||
{
|
||||
|
||||
if (isLoaded)
|
||||
{
|
||||
Tolk.Unload();
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Say(string text, bool interrupt)
|
||||
@@ -59,10 +47,22 @@ namespace stardew_access.ScreenReader
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
if (screenReader == null)
|
||||
if (!isLoaded)
|
||||
return;
|
||||
|
||||
screenReader.Speak(text, interrupt);
|
||||
if (!MainClass.Config.TTS)
|
||||
return;
|
||||
|
||||
if (text.Contains('^')) text = text.Replace('^', '\n');
|
||||
|
||||
if (Tolk.Output(text, interrupt))
|
||||
{
|
||||
MainClass.DebugLog($"Speaking(interrupt: {interrupt}) = {text}");
|
||||
}
|
||||
else
|
||||
{
|
||||
MainClass.ErrorLog($"Failed to output text: {text}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SayWithChecker(string text, bool interrupt)
|
||||
|
BIN
stardew-access/assets/sounds/colliding.wav
Normal file
BIN
stardew-access/assets/sounds/colliding.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/drop_item.wav
Normal file
BIN
stardew-access/assets/sounds/drop_item.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_bottom.wav
Normal file
BIN
stardew-access/assets/sounds/npc_bottom.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_left.wav
Normal file
BIN
stardew-access/assets/sounds/npc_left.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_mono_bottom.wav
Normal file
BIN
stardew-access/assets/sounds/npc_mono_bottom.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_mono_left.wav
Normal file
BIN
stardew-access/assets/sounds/npc_mono_left.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_mono_right.wav
Normal file
BIN
stardew-access/assets/sounds/npc_mono_right.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_mono_top.wav
Normal file
BIN
stardew-access/assets/sounds/npc_mono_top.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_right.wav
Normal file
BIN
stardew-access/assets/sounds/npc_right.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/npc_top.wav
Normal file
BIN
stardew-access/assets/sounds/npc_top.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_bottom.wav
Normal file
BIN
stardew-access/assets/sounds/obj_bottom.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_left.wav
Normal file
BIN
stardew-access/assets/sounds/obj_left.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_mono_bottom.wav
Normal file
BIN
stardew-access/assets/sounds/obj_mono_bottom.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_mono_left.wav
Normal file
BIN
stardew-access/assets/sounds/obj_mono_left.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_mono_right.wav
Normal file
BIN
stardew-access/assets/sounds/obj_mono_right.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_mono_top.wav
Normal file
BIN
stardew-access/assets/sounds/obj_mono_top.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_right.wav
Normal file
BIN
stardew-access/assets/sounds/obj_right.wav
Normal file
Binary file not shown.
BIN
stardew-access/assets/sounds/obj_top.wav
Normal file
BIN
stardew-access/assets/sounds/obj_top.wav
Normal file
Binary file not shown.
2457
stardew-access/assets/static-tiles.json
Normal file
2457
stardew-access/assets/static-tiles.json
Normal file
File diff suppressed because it is too large
Load Diff
16
stardew-access/i18n/de.json
Normal file
16
stardew-access/i18n/de.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Warnung! Die Gesundheit liegt bei {{value}} Prozent!",
|
||||
"warnings.stamina": "Warnung! Ausdauer beträgt ar {{value}} Prozent!",
|
||||
"warnings.time": "Warnung! Zeit ist {{value}}",
|
||||
"grandpastory.scene0":"Opa, auf seinem Sterbebett.",
|
||||
"grandpastory.scene4":"Mitarbeiter der JoJa corp.",
|
||||
"grandpastory.scene5":"Mitarbeiter in ihren Kabinen, einige von ihnen sehen erschöpft aus, Sie selbst eingeschlossen.",
|
||||
"grandpastory.scene6":"Du erreichst deinen Schreibtisch und findest Opas Brief.",
|
||||
"grandpastory.letteropen":"Linksklick, um Opas Brief zu öffnen",
|
||||
"intro.scene3":"Fahrt zur Bushaltestelle Stardew Valley",
|
||||
"intro.scene4":"Stardew Valley 0.5 Meilen entfernt",
|
||||
"manuallytriggered.healthnstamina.percent":"Gesundheit ist {{health}} % und Ausdauer ist {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"Gesundheit ist {{health}} und Ausdauer ist {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"Druck-{{value}}",
|
||||
"readtile.sprinkler.enricher":"Bereichernd {{value}}"
|
||||
}
|
16
stardew-access/i18n/default.json
Normal file
16
stardew-access/i18n/default.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Warning! Health is at {{value}} percent!",
|
||||
"warnings.stamina": "Warning! Stamina is at {{value}} percent!",
|
||||
"warnings.time": "Warning! Time is {{value}}",
|
||||
"grandpastory.scene0":"Grandpa, on his deathbed.",
|
||||
"grandpastory.scene4":"Employees working in JoJa corp.",
|
||||
"grandpastory.scene5":"Employees in their cubicles, some of them look exhausted including yourself.",
|
||||
"grandpastory.scene6":"You reach your desk finding grandpa's letter.",
|
||||
"grandpastory.letteropen":"Left click to open grandpa's letter",
|
||||
"intro.scene3":"Travelling to Stardew Valley bus stop",
|
||||
"intro.scene4":"Stardew valley 0.5 miles away",
|
||||
"manuallytriggered.healthnstamina.percent":"Health is {{health}} % and Stamina is {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"Health is {{health}} and Stamina is {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"Pressurized {{value}}",
|
||||
"readtile.sprinkler.enricher":"Enriching {{value}}"
|
||||
}
|
16
stardew-access/i18n/es.json
Normal file
16
stardew-access/i18n/es.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "¡Advertencia! ¡La salud está al {{value}} por ciento!",
|
||||
"warnings.stamina": "¡Advertencia! ¡La resistencia es un {{value}} por ciento!",
|
||||
"warnings.time": "¡Advertencia! El tiempo es {{valor}}",
|
||||
"grandpastory.scene0":"Abuelo, en su lecho de muerte.",
|
||||
"grandpastory.scene4":"Empleados que trabajan en JoJa corp.",
|
||||
"grandpastory.scene5":"Empleados en sus cubículos, algunos de ellos parecen exhaustos, incluido usted.",
|
||||
"grandpastory.scene6":"Llegas a tu escritorio y encuentras la carta del abuelo.",
|
||||
"grandpastory.letteropen":"Haz clic izquierdo para abrir la carta del abuelo.",
|
||||
"intro.scene3":"Viajando a la parada de autobús de Stardew Valley",
|
||||
"intro.scene4":"Valle de Stardew a 0.5 millas de distancia",
|
||||
"manuallytriggered.healthnstamina.percent":"La salud es {{health}} % y la resistencia es {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"La salud es {{health}} y la resistencia es {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"presurizada {{value}}",
|
||||
"readtile.sprinkler.enricher":"Enriquecedora {{value}}"
|
||||
}
|
16
stardew-access/i18n/fr.json
Normal file
16
stardew-access/i18n/fr.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Avertissement! La santé est à {{value}} pour cent!",
|
||||
"warnings.stamina": "Avertissement! L'endurance est à {{value}} pour cent!",
|
||||
"warnings.time": "Avertissement! Le temps est de {{value}}",
|
||||
"grandpastory.scene0":"Grand-père, sur son lit de mort.",
|
||||
"grandpastory.scene4":"Les employés travaillant chez JoJa corp.",
|
||||
"grandpastory.scene5":"Employés dans leurs cabines, certains ont l'air épuisés, y compris vous-même.",
|
||||
"grandpastory.scene6":"Vous atteignez votre bureau en trouvant la lettre de grand-père.",
|
||||
"grandpastory.letteropen":"Clic gauche pour ouvrir la lettre de grand-père",
|
||||
"intro.scene3":"Se rendre à l'arrêt de bus Stardew Valley",
|
||||
"intro.scene4":"Vallée de Stardew à 0.5 miles",
|
||||
"manuallytriggered.healthnstamina.percent":"La santé est de {{health}} % et l'endurance est de {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"La santé est {{health}} et l'endurance est {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"Sous pression {{value}}",
|
||||
"readtile.sprinkler.enricher":"Enrichissant {{value}}"
|
||||
}
|
16
stardew-access/i18n/hu.json
Normal file
16
stardew-access/i18n/hu.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Figyelem! Az egészségi állapot {{érték}} százalék!",
|
||||
"warnings.stamina": "Figyelem! Az állóképesség {{value}} százalék!",
|
||||
"warnings.time": "Figyelem! Az idő {{érték}}",
|
||||
"grandpastory.scene0":"Nagypapa, a halálos ágyán.",
|
||||
"grandpastory.scene4":"A JoJa corp.-nál dolgozó alkalmazottak",
|
||||
"grandpastory.scene5":"Alkalmazottak a fülkéiben, néhányuk kimerültnek tűnik, beleértve Önt is.",
|
||||
"grandpastory.scene6":"Az asztalodhoz érve megtalálod a nagypapa levelét.",
|
||||
"grandpastory.letteropen":"Kattintson a bal gombbal a nagypapa levelének megnyitásához",
|
||||
"intro.scene3":"Utazás a Stardew Valley buszmegállóhoz",
|
||||
"intro.scene4":"Stardew-völgy 0.5 mérföldre van",
|
||||
"manuallytriggered.healthnstamina.percent":"Az egészségi állapot {{health}} %, az állóképesség pedig {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"Az egészség {{health}}, az állóképesség pedig {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"Nyomás alatt {{value}}",
|
||||
"readtile.sprinkler.enricher":"Gazdagítás {{value}}"
|
||||
}
|
16
stardew-access/i18n/it.json
Normal file
16
stardew-access/i18n/it.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Avvertimento! La salute è al {{value}} percento!",
|
||||
"warnings.stamina": "Avvertimento! La resistenza è al {{value}} percento!",
|
||||
"warnings.time": "Avvertimento! L'ora è {{value}}",
|
||||
"grandpastory.scene0":"Il nonno, sul letto di morte.",
|
||||
"grandpastory.scene4":"Dipendenti che lavorano in JoJa corp.",
|
||||
"grandpastory.scene5":"Impiegati nei loro cubicoli, alcuni di loro sembrano esausti, compreso te.",
|
||||
"grandpastory.scene6":"Raggiungi la tua scrivania e trovi la lettera del nonno.",
|
||||
"grandpastory.letteropen":"Fare clic con il tasto sinistro per aprire la lettera del nonno",
|
||||
"intro.scene3":"In viaggio verso la fermata dell'autobus di Stardew Valley",
|
||||
"intro.scene4":"Stardew Valley 0.5 miglia di distanza",
|
||||
"manuallytriggered.healthnstamina.percent":"La salute è {{health}} % e la resistenza è {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"La salute è {{health}} e la resistenza è {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"Pressurizzato {{value}}",
|
||||
"readtile.sprinkler.enricher":"Arricchimento {{value}}"
|
||||
}
|
16
stardew-access/i18n/ja.json
Normal file
16
stardew-access/i18n/ja.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "警告!健康状態は{{value}}パーセントです!",
|
||||
"warnings.stamina": "警告!スタミナは{{value}}パーセントです!",
|
||||
"warnings.time": "警告!時間は{{value}}です",
|
||||
"grandpastory.scene0":"おじいちゃん、彼の死の床に。",
|
||||
"grandpastory.scene4":"JoJacorpで働く従業員。",
|
||||
"grandpastory.scene5":"彼らのキュービクルの従業員、彼らの何人かはあなた自身を含めて疲れ果てているように見えます。",
|
||||
"grandpastory.scene6":"おじいちゃんの手紙を見つけて机に着きます。",
|
||||
"grandpastory.letteropen":"左クリックしておじいちゃんの手紙を開く",
|
||||
"intro.scene3":"スターデューバレーバス停への移動",
|
||||
"intro.scene4":"0.5マイル離れたスターデューバレー",
|
||||
"manuallytriggered.healthnstamina.percent":"体力は {{health}} %、スタミナは {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"体力は{{health}}、スタミナは{{stamina}}です",
|
||||
"readtile.sprinkler.pressurenozzle":"加圧 {{value}}",
|
||||
"readtile.sprinkler.enricher":"豊かにする {{value}}"
|
||||
}
|
16
stardew-access/i18n/ko.json
Normal file
16
stardew-access/i18n/ko.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "경고! 건강은 {{value}}퍼센트입니다!",
|
||||
"warnings.stamina": "경고! 체력은 {{value}}퍼센트입니다!",
|
||||
"warnings.time": "경고! 시간은 {{value}}입니다",
|
||||
"grandpastory.scene0":"임종을 앞둔 할아버지.",
|
||||
"grandpastory.scene4":"(주)조자에서 근무하는 직원들",
|
||||
"grandpastory.scene5":"칸막이에 있는 직원들, 당신을 포함하여 몇몇은 지쳐 보입니다.",
|
||||
"grandpastory.scene6":"책상에 다가가 할아버지의 편지를 찾습니다.",
|
||||
"grandpastory.letteropen":"할아버지의 편지를 열려면 왼쪽 클릭",
|
||||
"intro.scene3":"스타듀밸리 버스정류장으로 이동",
|
||||
"intro.scene4":"스타듀 밸리에서 0.8km 떨어짐",
|
||||
"manuallytriggered.healthnstamina.percent":"체력은 {{health}} %이고 체력은 {{stamina}} %입니다.",
|
||||
"manuallytriggered.healthnstamina.normal":"체력은 {{health}}이고 체력은 {{stamina}}입니다.",
|
||||
"readtile.sprinkler.pressurenozzle":"가압 {{value}}",
|
||||
"readtile.sprinkler.enricher":"풍부하게 하기 {{value}}"
|
||||
}
|
16
stardew-access/i18n/pt.json
Normal file
16
stardew-access/i18n/pt.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Aviso! A saúde está em {{value}} por cento!",
|
||||
"warnings.stamina": "Aviso! A resistência está em {{value}} por cento!",
|
||||
"warnings.time": "Aviso! O tempo é {{value}}",
|
||||
"grandpastory.scene0":"Vovô, em seu leito de morte.",
|
||||
"grandpastory.scene4":"Funcionários que trabalham na JoJa corp.",
|
||||
"grandpastory.scene5":"Funcionários em seus cubículos, alguns deles parecem exaustos, incluindo você.",
|
||||
"grandpastory.scene6":"Você chega à sua mesa encontrando a carta do vovô.",
|
||||
"grandpastory.letteropen":"Clique com o botão esquerdo para abrir a carta do vovô",
|
||||
"intro.scene3":"Viajar para o ponto de ônibus Stardew Valley",
|
||||
"intro.scene4":"Vale Stardew a 0.5 km de distância",
|
||||
"manuallytriggered.healthnstamina.percent":"Saúde é {{health}} % e Stamina é {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"Saúde é {{health}} e Stamina é {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"Pressurizada {{value}}",
|
||||
"readtile.sprinkler.enricher":"Enriquecimento {{value}}"
|
||||
}
|
16
stardew-access/i18n/ru.json
Normal file
16
stardew-access/i18n/ru.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Предупреждение! Здоровье составляет {{value}} процентов!",
|
||||
"warnings.stamina": "Предупреждение! Выносливость составляет {{value}} процентов!",
|
||||
"warnings.time": "Предупреждение! Время {{value}}",
|
||||
"grandpastory.scene0":"Дедушка на смертном одре.",
|
||||
"grandpastory.scene4":"Сотрудники, работающие в JoJa corp.",
|
||||
"grandpastory.scene5":"Сотрудники в своих кабинетах, некоторые из них выглядят измученными, в том числе и вы.",
|
||||
"grandpastory.scene6":"Вы подходите к своему столу и находите дедушкино письмо.",
|
||||
"grandpastory.letteropen":"Щелкните левой кнопкой мыши, чтобы открыть письмо дедушки",
|
||||
"intro.scene3":"Поездка на автобусную остановку Stardew Valley",
|
||||
"intro.scene4":"Долина Стардью: 0.8 км",
|
||||
"manuallytriggered.healthnstamina.percent":"Здоровье составляет {{health}}%, а выносливость - {{stamina}}%",
|
||||
"manuallytriggered.healthnstamina.normal":"Здоровье – {{health}}, а выносливость – {{stamina}}.",
|
||||
"readtile.sprinkler.pressurenozzle":"под давлением {{value}}",
|
||||
"readtile.sprinkler.enricher":"Обогащение {{value}}"
|
||||
}
|
16
stardew-access/i18n/tr.json
Normal file
16
stardew-access/i18n/tr.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "Uyarı! Sağlık yüzde {{değer}}!",
|
||||
"warnings.stamina": "uyarı! Dayanıklılık yüzde {{değer}}!",
|
||||
"warnings.time": "Uyarı! Zaman {{değer}}",
|
||||
"grandpastory.scene0":"Büyükbaba, ölüm döşeğinde.",
|
||||
"grandpastory.scene4":"JoJa şirketinde çalışan çalışanlar",
|
||||
"grandpastory.scene5":"Kabinlerinde çalışanlar, siz de dahil olmak üzere bazıları bitkin görünüyor.",
|
||||
"grandpastory.scene6":"Dedenizin mektubunu bulmak için masanıza ulaşıyorsunuz.",
|
||||
"grandpastory.letteropen":"Büyükbabanın mektubunu açmak için sol tıklayın",
|
||||
"intro.scene3":"Stardew Valley otobüs durağına seyahat",
|
||||
"intro.scene4":"Stardew vadisi 0.5 mil uzakta",
|
||||
"manuallytriggered.healthnstamina.percent":"Sağlık %{{health}} ve Dayanıklılık %{{stamina}}",
|
||||
"manuallytriggered.healthnstamina.normal":"Sağlık {{health}} ve Dayanıklılık {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"basınçlı {{value}}",
|
||||
"readtile.sprinkler.enricher":"zenginleştirici {{value}}"
|
||||
}
|
16
stardew-access/i18n/zh.json
Normal file
16
stardew-access/i18n/zh.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"warnings.health": "警告!健康状况为 {{value}} 百分!",
|
||||
"warnings.stamina": "警告!耐力为 {{value}} 百分!",
|
||||
"warnings.time": "警告!时间是 {{value}}",
|
||||
"grandpastory.scene0":"爷爷,去世前。",
|
||||
"grandpastory.scene4":"在 JoJa corp. 工作的员工",
|
||||
"grandpastory.scene5":"员工在他们的办公室里,他们看起来很累,这其中也包括你自己。",
|
||||
"grandpastory.scene6":"你走到办公桌前,找到了爷爷的信。",
|
||||
"grandpastory.letteropen":"左方括号打开爷爷的信",
|
||||
"intro.scene3":"前往星露谷物语巴士站",
|
||||
"intro.scene4":"星露谷物语 0.5 英里外",
|
||||
"manuallytriggered.healthnstamina.percent":"健康为 {{health}} %,耐力为 {{stamina}} %",
|
||||
"manuallytriggered.healthnstamina.normal":"健康为 {{health}},耐力为 {{stamina}}",
|
||||
"readtile.sprinkler.pressurenozzle":"加压 {{value}}",
|
||||
"readtile.sprinkler.enricher":"丰富 {{value}}"
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"Name": "Stardew Access",
|
||||
"Author": "Mohammad Shoaib",
|
||||
"Version": "1.1.0",
|
||||
"Version": "1.3.4",
|
||||
"Description": "An accessibility mod with screen reader support!",
|
||||
"UniqueID": "shoaib.stardewaccess",
|
||||
"EntryDll": "stardew-access.dll",
|
||||
|
@@ -7,13 +7,14 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<!-- To generate dlls of nugget packages -->
|
||||
<!-- <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AccessibleOutput" Version="1.0.0" />
|
||||
<PackageReference Include="Lib.Harmony" Version="2.2.0" />
|
||||
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.0.0" />
|
||||
<Reference Include="./TolkDotNet.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
Reference in New Issue
Block a user