diff --git a/.gitignore b/.gitignore index d97ee0b..ff52632 100644 --- a/.gitignore +++ b/.gitignore @@ -353,4 +353,7 @@ MigrationBackup/ .ionide/ *.DotSettings -codepage.txt \ No newline at end of file +codepage.txt + +# IDEA / JetBrains Rider +.idea/ diff --git a/JoysOfEfficiency.sln b/GloryOfEfficiency.sln similarity index 75% rename from JoysOfEfficiency.sln rename to GloryOfEfficiency.sln index 7dc0a2a..1e5eb9b 100644 --- a/JoysOfEfficiency.sln +++ b/GloryOfEfficiency.sln @@ -1,8 +1,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29424.173 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34714.143 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JoysOfEfficiency", "JoysOfEfficiency\JoysOfEfficiency.csproj", "{0302444C-4190-4C5D-A873-A1F80267961A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GloryOfEfficiency", "GloryOfEfficiency\GloryOfEfficiency.csproj", "{0302444C-4190-4C5D-A873-A1F80267961A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -12,14 +12,15 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|Any CPU.ActiveCfg = Release|x86 - {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|Any CPU.Build.0 = Release|x86 - {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|x86.ActiveCfg = Debug|x86 - {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|x86.Build.0 = Debug|x86 + {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|x86.ActiveCfg = Debug|Any CPU + {0302444C-4190-4C5D-A873-A1F80267961A}.Debug|x86.Build.0 = Debug|Any CPU {0302444C-4190-4C5D-A873-A1F80267961A}.Release|Any CPU.ActiveCfg = Release|Any CPU {0302444C-4190-4C5D-A873-A1F80267961A}.Release|Any CPU.Build.0 = Release|Any CPU - {0302444C-4190-4C5D-A873-A1F80267961A}.Release|x86.ActiveCfg = Release|x86 - {0302444C-4190-4C5D-A873-A1F80267961A}.Release|x86.Build.0 = Release|x86 + {0302444C-4190-4C5D-A873-A1F80267961A}.Release|x86.ActiveCfg = Release|Any CPU + {0302444C-4190-4C5D-A873-A1F80267961A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/JoysOfEfficiency/Automation/AnimalAutomation.cs b/GloryOfEfficiency/Automation/AnimalAutomation.cs similarity index 59% rename from JoysOfEfficiency/Automation/AnimalAutomation.cs rename to GloryOfEfficiency/Automation/AnimalAutomation.cs index 2073940..b302c03 100644 --- a/JoysOfEfficiency/Automation/AnimalAutomation.cs +++ b/GloryOfEfficiency/Automation/AnimalAutomation.cs @@ -1,20 +1,18 @@ using System.Collections.Generic; using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; -using Netcode; -using StardewModdingAPI; using StardewValley; using StardewValley.Buildings; using StardewValley.Characters; +using StardewValley.Extensions; using StardewValley.Tools; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class AnimalAutomation { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; private static Config Config => InstanceHolder.Config; private static readonly Logger Logger = new Logger("AnimalAutomation"); @@ -26,8 +24,8 @@ public static void LetAnimalsInHome() { FarmAnimal animal = kv.Value; Logger.Log( - $"Warped {animal.displayName}({animal.shortDisplayType()}) to {animal.displayHouse}@[{animal.homeLocation.X}, {animal.homeLocation.Y}]"); - animal.warpHome(farm, animal); + $"Warped {animal.displayName}({animal.shortDisplayType()}) to {animal.displayHouse}@[{animal.home.animalDoor.X}, {animal.home.animalDoor.Y}]"); + animal.warpHome(); } } @@ -49,34 +47,18 @@ public static void AutoOpenAnimalDoor() Farm farm = Game1.getFarm(); foreach (Building building in farm.buildings) { - switch (building) + switch (building.buildingType.Value) { - case Coop coop: + case "Coop": + case "Barn": { - if (coop.indoors.Value is AnimalHouse house) + if (building.indoors.Value is AnimalHouse house) { - if (house.animals.Any() && !coop.animalDoorOpen.Value) + if (house.animals.Any() && !building.animalDoorOpen.Value) { - Logger.Log($"Opening coop door @[{coop.animalDoor.X},{coop.animalDoor.Y}]"); - coop.animalDoorOpen.Value = true; - Reflection.GetField(coop, "animalDoorMotion").SetValue(new NetInt(-2)); + building.ToggleAnimalDoor(Game1.player); } } - - break; - } - case Barn barn: - { - if (barn.indoors.Value is AnimalHouse house) - { - if (house.animals.Any() && !barn.animalDoorOpen.Value) - { - Logger.Log($"Opening barn door @[{barn.animalDoor.X},{barn.animalDoor.Y}]"); - barn.animalDoorOpen.Value = true; - Reflection.GetField(barn, "animalDoorMotion").SetValue(new NetInt(-3)); - } - } - break; } } @@ -88,32 +70,18 @@ public static void AutoCloseAnimalDoor() Farm farm = Game1.getFarm(); foreach (Building building in farm.buildings) { - switch (building) + switch (building.buildingType.Value) { - case Coop coop: + case "Coop": + case "Barn": { - if (coop.indoors.Value is AnimalHouse house) + if (building.indoors.Value is AnimalHouse house) { - if (house.animals.Any() && coop.animalDoorOpen.Value) + if (house.animals.Any() && building.animalDoorOpen.Value) { - coop.animalDoorOpen.Value = false; - Reflection.GetField(coop, "animalDoorMotion").SetValue(new NetInt(2)); + building.ToggleAnimalDoor(Game1.player); } } - - break; - } - case Barn barn: - { - if (barn.indoors.Value is AnimalHouse house) - { - if (house.animals.Any() && barn.animalDoorOpen.Value) - { - barn.animalDoorOpen.Value = false; - Reflection.GetField(barn, "animalDoorMotion").SetValue(new NetInt(2)); - } - } - break; } } @@ -132,8 +100,9 @@ public static void PetNearbyPets() bool wasPet = WasPetToday(pet); if (!wasPet) { - Logger.Log($"Petted {(pet is Dog ? "Dog" : "Cat")}'{pet.Name}' @{pet.getTileLocationPoint()}"); + Logger.Log($"Petted {(pet.petType.Value == "Dog" ? "Dog" : "Cat")}'{pet.Name}' @{pet.position}"); pet.checkAction(player, location); // Pet pet... lol + } } } @@ -142,18 +111,18 @@ public static void PetNearbyAnimals() { int radius = Config.AutoPetRadius * Game1.tileSize; Rectangle bb = Util.Expand(Game1.player.GetBoundingBox(), radius); - foreach (FarmAnimal animal in Util.GetAnimalsList(Game1.player)) + foreach (FarmAnimal animal in GetAnimalsList(Game1.player)) { - if (!bb.Contains((int) animal.Position.X, (int) animal.Position.Y) || animal.wasPet.Value) + if (Game1.timeOfDay >= 1900 && !animal.isMoving()) { continue; } - - if (Game1.timeOfDay >= 1900 && !animal.isMoving()) + if (!bb.Contains((int) animal.Position.X, (int) animal.Position.Y) || animal.wasPet.Value) { continue; } - Logger.Log($"Petted {animal.displayType}'{animal.Name}' @{animal.getTileLocationPoint()}"); + + Logger.Log($"Petted {animal.displayType}'{animal.Name}' @{animal.position}"); animal.pet(Game1.player); } } @@ -162,10 +131,10 @@ public static void ShearingAndMilking(Farmer player) { int radius = InstanceHolder.Config.AnimalHarvestRadius * Game1.tileSize; Rectangle bb = Util.Expand(player.GetBoundingBox(), radius); - foreach (FarmAnimal animal in Util.GetAnimalsList(player)) + foreach (FarmAnimal animal in GetAnimalsList(player)) { string lowerType = animal.type.Value.ToLower(); - if (animal.currentProduce.Value < 0 || animal.age.Value < animal.ageWhenMature.Value || + if (animal.currentProduce.Value is null || animal.isBaby() || player.CurrentTool == null || !animal.GetBoundingBox().Intersects(bb)) { continue; @@ -177,20 +146,21 @@ public static void ShearingAndMilking(Farmer player) continue; if (!player.addItemToInventoryBool( - new Object(Vector2.Zero, animal.currentProduce.Value, null, false, true, false, false) - { - Quality = animal.produceQuality.Value - })) + new StardewValley.Object(animal.currentProduce.Value, + animal.hasEatenAnimalCracker.Value ? 2 : 1, + false, + -1, + animal.produceQuality.Value))) { continue; } switch (player.CurrentTool) { - case Shears _: + case Shears: Shears.playSnip(player); break; - case MilkPail _: + case MilkPail: player.currentLocation.localSound("Milking"); DelayedAction.playSoundAfterDelay("fishingRodBend", 300); DelayedAction.playSoundAfterDelay("fishingRodBend", 1200); @@ -200,12 +170,8 @@ public static void ShearingAndMilking(Farmer player) animal.doEmote(20); Game1.playSound("coin"); - animal.currentProduce.Value = -1; - if (animal.showDifferentTextureWhenReadyForHarvest.Value) - { - animal.Sprite.LoadTexture("Animals\\Sheared" + animal.type.Value); - } - + animal.currentProduce.Value = null; + animal.ReloadTextureIfNeeded(); player.gainExperience(0, 5); } } @@ -215,5 +181,27 @@ private static bool WasPetToday(Pet pet) return pet.lastPetDay.ContainsKey(Game1.player.UniqueMultiplayerID) && pet.lastPetDay[Game1.player.UniqueMultiplayerID] == Game1.Date.TotalDays; } + + + private static IEnumerable GetAnimalsList(Character player) + { + HashSet list = new HashSet(); + switch (player.currentLocation) + { + case Farm farm: + { + list.AddRange(farm.animals.Values); + break; + } + + case AnimalHouse house: + { + list.AddRange(house.animals.Values); + break; + } + } + return list; + } + } -} \ No newline at end of file +} diff --git a/JoysOfEfficiency/Automation/AutoFisher.cs b/GloryOfEfficiency/Automation/AutoFisher.cs similarity index 58% rename from JoysOfEfficiency/Automation/AutoFisher.cs rename to GloryOfEfficiency/Automation/AutoFisher.cs index 95403f5..4bf5430 100644 --- a/JoysOfEfficiency/Automation/AutoFisher.cs +++ b/GloryOfEfficiency/Automation/AutoFisher.cs @@ -1,29 +1,33 @@ -using System.Collections.Generic; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using System; +using System.Collections.Generic; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; -using StardewModdingAPI; using StardewValley; +using StardewValley.ItemTypeDefinitions; using StardewValley.Menus; using StardewValley.Objects; +using StardewValley.SpecialOrders; using StardewValley.Tools; +using SVObject = StardewValley.Object; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class AutoFisher { private static Config Config => InstanceHolder.Config; - private static readonly Logger Logger = new Logger("AFKFisher"); + private static readonly Logger Logger = new Logger("AutoFisher"); public static bool AfkMode { get; private set; } + public static int FishQuality { get; set; } + public static bool Treasure { get; set; } + private static bool CatchingTreasure { get; set; } private static int AutoFishingCounter { get; set; } private static int AfkCooltimeCounter { get; set; } - private static IReflectionHelper Reflection => InstanceHolder.Reflection; - public static void AfkFishing() { Farmer player = Game1.player; @@ -74,9 +78,8 @@ public static void AutoReelRod() { return; } - int whichFish = Reflection.GetField(rod, "whichFish").GetValue(); - if (!rod.isNibbling || !rod.isFishing || whichFish != -1 || rod.isReeling || rod.hit || + if (!rod.isNibbling || !rod.isFishing || rod.whichFish != null || rod.isReeling || rod.hit || rod.isTimingCast || rod.pullingOutOfWater || rod.fishCaught || rod.castedButBobberStillInAir) { return; @@ -85,14 +88,13 @@ public static void AutoReelRod() rod.DoFunction(player.currentLocation, 1, 1, 1, player); } - public static void CollectFish(Farmer who, FishingRod rod) + private static void CollectFish(Farmer who, FishingRod rod) { - IReflectedField recastTimerMs = Reflection.GetField(rod, "recastTimerMs"); - - int whichFish = Reflection.GetField(rod, "whichFish").GetValue(); - int fishQuality = Reflection.GetField(rod, "fishQuality").GetValue(); - - string itemCategory = Reflection.GetField(rod, "itemCategory").GetValue(); + ItemMetadata whichFish = rod.whichFish; + String whichFishName = rod.whichFish.QualifiedItemId; + FishQuality = rod.fishQuality; + string fishID = whichFish.GetParsedData().ItemId; + int itemCategory = whichFish.GetParsedData().Category; if (!Game1.isFestival()) { @@ -100,18 +102,6 @@ public static void CollectFish(Farmer who, FishingRod rod) who.FarmerSprite.setCurrentFrame(84); } - if (Game1.random.NextDouble() < 0.025) - { - who.currentLocation.temporarySprites.Add(new TemporaryAnimatedSprite("LooseSprites\\Cursors", - new Rectangle(653, 858, 1, 1), 9999f, 1, 1, - who.Position + new Vector2(Game1.random.Next(-3, 2) * 4, -32f), false, false, - (float) (who.getStandingY() / 10000.0 + 1.0 / 500.0), 0.04f, Color.LightBlue, 5f, 0.0f, - 0.0f, 0.0f) - { - acceleration = new Vector2(0.0f, 0.25f) - }); - } - if (!who.IsLocalPlayer) { return; @@ -120,42 +110,47 @@ public static void CollectFish(Farmer who, FishingRod rod) who.currentLocation.localSound("coin"); if (!rod.treasureCaught) { - recastTimerMs.SetValue(200); - Object @object = null; + SVObject @object = null; switch (itemCategory) { - case "Object": + case SVObject.furnitureCategory: + { + Logger.Log($"\tFurniture? {fishID}\tItemCategory: {itemCategory}"); + @object = new Furniture(fishID, Vector2.Zero); + break; + } + case SVObject.junkCategory: + case SVObject.litterCategory: + case SVObject.FishCategory: + default: { - @object = new Object(whichFish, 1, false, -1, fishQuality); - if (whichFish == GameLocation.CAROLINES_NECKLACE_ITEM) + Logger.Log($"\tFishy, Litter, or Junky! {fishID}"); + @object = new SVObject(fishID, 1, false, -1, FishQuality); + if (fishID == GameLocation.CAROLINES_NECKLACE_ITEM_QID) { @object.questItem.Value = true; + break; } - if (whichFish == 79 || whichFish == 842) + if (fishID == "79" || fishID == "842") // Secret Note (79) or Journal Scrap (842) { @object = who.currentLocation.tryToCreateUnseenSecretNote(who); - if (@object == null) - return; + if (@object == null) return; } - if (rod.caughtDoubleFish) + if (rod.numberOfFishCaught > 1) { - @object.Stack = 2; + @object.Stack = rod.numberOfFishCaught; } break; } - case "Furniture": - { - @object = new Furniture(whichFish, Vector2.Zero); - break; - } } + bool fromFishPond = rod.fromFishPond; who.completelyStopAnimatingOrDoingAction(); rod.doneFishing(who, !fromFishPond); - if (!Game1.isFestival() && !fromFishPond && (itemCategory == "Object" && Game1.player.team.specialOrders != null)) + if (!Game1.isFestival() && !fromFishPond && (itemCategory == SVObject.FishCategory && Game1.player.team.specialOrders.Count > 0)) { foreach (SpecialOrder specialOrder in Game1.player.team.specialOrders) { @@ -168,40 +163,31 @@ public static void CollectFish(Farmer who, FishingRod rod) return; } - Game1.activeClickableMenu = new ItemGrabMenu(new List - { - @object - }, rod).setEssential(true); + Game1.activeClickableMenu = new ItemGrabMenu(new List { @object }, rod).setEssential(true); } else { + Logger.Log($"Treazhure Cot!"); rod.fishCaught = false; rod.showingTreasure = true; who.UsingTool = true; int initialStack = 1; - if (rod.caughtDoubleFish) + if (rod.numberOfFishCaught > 1) { - initialStack = 2; + initialStack = rod.numberOfFishCaught; } - Object @object = new Object(whichFish, initialStack, false, -1, fishQuality); - if (Game1.player.team.specialOrders != null) + SVObject @object = new SVObject(fishID, initialStack, false, -1, FishQuality); + if (Game1.player.team.specialOrders.Count > 0) { + Logger.Log($"\tSpechul Treazhure!"); foreach (SpecialOrder specialOrder in Game1.player.team.specialOrders) { specialOrder.onFishCaught?.Invoke(Game1.player, @object); } } bool inventoryBool = who.addItemToInventoryBool(@object); - rod.animations.Add(new TemporaryAnimatedSprite("LooseSprites\\Cursors", new Rectangle(64, 1920, 32, 32), 500f, 1, 0, who.Position + new Vector2(-32f, -160f), false, false, (float)(who.getStandingY() / 10000.0 + 1.0 / 1000.0), 0.0f, Color.White, 4f, 0.0f, 0.0f, 0.0f) - { - motion = new Vector2(0.0f, -0.128f), - timeBasedMotion = true, - endFunction = rod.openChestEndFunction, - extraInfoForEndBehavior = inventoryBool ? 0 : 1, - alpha = 0.0f, - alphaFade = -1f / 500f - }); + rod.openChestEndFunction(inventoryBool ? 0 : 1); } } @@ -213,22 +199,17 @@ public static void AutoFishing(BobberBar bar) return; } - - IReflectedField bobberSpeed = Reflection.GetField(bar, "bobberBarSpeed"); - - float barPos = Reflection.GetField(bar, "bobberBarPos").GetValue(); - int barHeight = Reflection.GetField(bar, "bobberBarHeight").GetValue(); - float fishPos = Reflection.GetField(bar, "bobberPosition").GetValue(); - float treasurePos = Reflection.GetField(bar, "treasurePosition").GetValue(); - float distanceFromCatching = Reflection.GetField(bar, "distanceFromCatching").GetValue(); - bool treasureCaught = Reflection.GetField(bar, "treasureCaught").GetValue(); - bool treasure = Reflection.GetField(bar, "treasure").GetValue(); - float treasureAppearTimer = Reflection.GetField(bar, "treasureAppearTimer").GetValue(); - float bobberBarSpeed = bobberSpeed.GetValue(); - + float barPos = bar.bobberBarPos; + int barHeight = bar.bobberBarHeight; + float fishPos = bar.bobberPosition; + float treasurePos = bar.treasurePosition; + float distanceFromCatching = bar.distanceFromCatching; + bool treasureCaught = bar.treasureCaught; + float treasureAppearTimer = bar.treasureAppearTimer; + float bobberBarSpeed = bar.bobberBarSpeed; float top = barPos; - if (treasure && treasureAppearTimer <= 0 && !treasureCaught) + if (Treasure && treasureAppearTimer <= 0 && !treasureCaught) { if (!CatchingTreasure && distanceFromCatching > 0.7f) { @@ -258,7 +239,7 @@ public static void AutoFishing(BobberBar bar) bobberBarSpeed = strength; } - bobberSpeed.SetValue(bobberBarSpeed); + bar.bobberBarSpeed = bobberBarSpeed; } public static void ToggleAfkFishing() diff --git a/JoysOfEfficiency/Automation/CollectibleCollector.cs b/GloryOfEfficiency/Automation/CollectibleCollector.cs similarity index 90% rename from JoysOfEfficiency/Automation/CollectibleCollector.cs rename to GloryOfEfficiency/Automation/CollectibleCollector.cs index 70fc65f..b3ab883 100644 --- a/JoysOfEfficiency/Automation/CollectibleCollector.cs +++ b/GloryOfEfficiency/Automation/CollectibleCollector.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using StardewValley; using StardewValley.TerrainFeatures; using StardewValley.Tools; using SVObject = StardewValley.Object; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class CollectibleCollector { @@ -40,12 +40,12 @@ private static void CollectObj(GameLocation loc, SVObject obj) int quality = obj.Quality; Random random = new Random((int)Game1.uniqueIDForThisGame / 2 + (int)Game1.stats.DaysPlayed + (int)vector.X + (int)vector.Y * 777); - if (who.professions.Contains(16) && obj.isForage(loc)) + if (who.professions.Contains(16) && obj.isForage()) { obj.Quality = 4; } - else if (obj.isForage(loc)) + else if (obj.isForage()) { if (random.NextDouble() < who.ForagingLevel / 30f) { @@ -73,7 +73,7 @@ private static void CollectObj(GameLocation loc, SVObject obj) if (!loc.isFarmBuildingInterior()) { - if (obj.isForage(loc)) + if (obj.isForage()) { who.gainExperience(2, 7); } @@ -98,7 +98,7 @@ private static void CollectObj(GameLocation loc, SVObject obj) private static bool IsGinger(Crop crop) { - return crop != null && crop.forageCrop && crop.whichForageCrop == Crop.forageCrop_ginger; + return crop != null && crop.forageCrop.Value && crop.whichForageCrop.Value == Crop.forageCrop_ginger.ToString(); } private static void CollectGinger(GameLocation loc, Vector2 pos, HoeDirt dirt) @@ -113,7 +113,7 @@ private static void CollectGinger(GameLocation loc, Vector2 pos, HoeDirt dirt) if (dirt.crop.hitWithHoe((int)pos.X, (int)pos.Y, loc,dirt)) { who.Stamina -= stamina; - dirt.destroyCrop(pos, true, loc); + dirt.destroyCrop(true); } } } diff --git a/JoysOfEfficiency/Automation/FarmCleaner.cs b/GloryOfEfficiency/Automation/FarmCleaner.cs similarity index 83% rename from JoysOfEfficiency/Automation/FarmCleaner.cs rename to GloryOfEfficiency/Automation/FarmCleaner.cs index 158bba3..17821bf 100644 --- a/JoysOfEfficiency/Automation/FarmCleaner.cs +++ b/GloryOfEfficiency/Automation/FarmCleaner.cs @@ -1,25 +1,23 @@ using System; using System.Collections.Generic; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; -using StardewModdingAPI; using StardewValley; using StardewValley.Locations; using StardewValley.Tools; using Object = StardewValley.Object; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class FarmCleaner { private static Multiplayer Multiplayer => InstanceHolder.Multiplayer; private static Config Config => InstanceHolder.Config; - private static IReflectionHelper Reflection => InstanceHolder.Reflection; private static readonly Logger Logger = new Logger("FarmCleaner"); - public static void OnEighthUpdate() + public static void OnNthTickUpdate() { GameLocation farm = Game1.currentLocation; if (!(farm is Farm || farm is IslandWest)) @@ -57,7 +55,7 @@ public static void OnEighthUpdate() private static void CutWeeds(GameLocation farm, Object obj, Vector2 loc) { - Reflection.GetMethod(obj, "cutWeed").Invoke(Game1.player, farm); + obj.cutWeed(Game1.player); farm.removeObject(loc, false); } @@ -72,9 +70,9 @@ private static bool ChopTwig(GameLocation farm, Object obj, Vector2 loc) player.Stamina -= stamina; - obj.fragility.Value = 2; + obj.Fragility = 2; farm.playSound("axchop"); - farm.debris.Add(new Debris(new Object(388, 1), loc * 64f + new Vector2(32f, 32f))); + farm.debris.Add(new Debris(new Object("388", 1), loc * 64f + new Vector2(32f, 32f))); Game1.createRadialDebris(farm, 12, (int)loc.X, (int)loc.Y, Game1.random.Next(4, 10), false); Multiplayer.broadcastSprites(farm, new TemporaryAnimatedSprite(12, new Vector2(loc.X * 64f, loc.Y * 64f), Color.White, 8, Game1.random.NextDouble() < 0.5, 50f)); @@ -98,23 +96,23 @@ private static bool BreakRock(GameLocation location, Tool pickaxe, Object @objec int x = num1 * 64; int y = num2 * 64; location.playSound("hammer"); - if (@object.minutesUntilReady > 0) + if (@object.MinutesUntilReady > 0) { - int num3 = Math.Max(1, pickaxe.upgradeLevel + 1); - @object.minutesUntilReady.Value -= num3; + int num3 = Math.Max(1, pickaxe.UpgradeLevel + 1); + @object.MinutesUntilReady -= num3; @object.shakeTimer = 200; - if (@object.minutesUntilReady > 0) + if (@object.MinutesUntilReady > 0) { Game1.createRadialDebris(Game1.currentLocation, 14, num1, num2, Game1.random.Next(2, 5), false); return false; } } - if (@object.ParentSheetIndex < 200 && !Game1.objectInformation.ContainsKey(@object.ParentSheetIndex + 1)) + if (@object.ParentSheetIndex < 200 && !Game1.objectData.ContainsKey(""+(@object.ParentSheetIndex + 1))) { Multiplayer.broadcastSprites(location, new TemporaryAnimatedSprite(@object.ParentSheetIndex + 1, 300f, - 1, 2, new Vector2(x - x % 64, y - y % 64), true, @object.flipped) + 1, 2, new Vector2(x - x % 64, y - y % 64), true, @object.Flipped) { alphaFade = 0.01f }); @@ -131,8 +129,8 @@ private static bool BreakRock(GameLocation location, Tool pickaxe, Object @objec acceleration = new Vector2(0.0f, 1f / 500f), alphaFade = 0.015f }); - location.OnStoneDestroyed(@object.parentSheetIndex, num1, num2, Game1.player); - if (@object.minutesUntilReady > 0) + location.OnStoneDestroyed(""+@object.ParentSheetIndex, num1, num2, Game1.player); + if (@object.MinutesUntilReady > 0) return false; location.Objects.Remove(new Vector2(num1, num2)); location.playSound("stoneCrack"); diff --git a/JoysOfEfficiency/Automation/FenceGateAutomation.cs b/GloryOfEfficiency/Automation/FenceGateAutomation.cs similarity index 92% rename from JoysOfEfficiency/Automation/FenceGateAutomation.cs rename to GloryOfEfficiency/Automation/FenceGateAutomation.cs index 920dc30..1f4fb4c 100644 --- a/JoysOfEfficiency/Automation/FenceGateAutomation.cs +++ b/GloryOfEfficiency/Automation/FenceGateAutomation.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using StardewValley; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal enum FenceType { @@ -18,7 +18,7 @@ internal class FenceGateAutomation public static void TryToggleGate(Farmer player) { GameLocation location = player.currentLocation; - foreach (Fence fence in Util.GetObjectsWithin(2, true).Where(x=>x.isGate)) + foreach (Fence fence in Util.GetObjectsWithin(2, true).Where(x=>x.isGate.Value)) { bool flag = false; List fencesToOperate = new List {fence}; @@ -57,8 +57,8 @@ private static bool IsPlayerFaceOrBack(FenceType type, Farmer farmer) private static bool IsPlayerInClose(Fence fence, Farmer player) { Vector2 oVec = fence.TileLocation; - Vector2 pVec = player.getTileLocation(); - return pVec == oVec || + Vector2 pVec = player.Tile; + return pVec == oVec || pVec == oVec + new Vector2(1, 0) || pVec == oVec + new Vector2(-1, 0) || pVec == oVec + new Vector2(0, 1) || pVec == oVec + new Vector2(0, -1); } @@ -72,7 +72,7 @@ private static bool IsPlayerInClose(List fences, FenceType type, Farmer p foreach (Fence fence in fences.Where(f => f != null)) { Vector2 oVec = fence.TileLocation; - Vector2 pVec = player.getTileLocation(); + Vector2 pVec = player.Tile; if (oVec == pVec) { return true; @@ -113,12 +113,12 @@ private static Fence GetConnectedGate(GameLocation location, Vector2 fenceLoc, F if (type == FenceType.Horizontal) { if (location.Objects.TryGetValue(fenceLoc + new Vector2(-1, 0), out Object obj) && - obj is Fence fence && fence.isGate) + obj is Fence fence && fence.isGate.Value) { return fence; } if (location.Objects.TryGetValue(fenceLoc + new Vector2(1, 0), out obj) && - obj is Fence fence2 && fence2.isGate) + obj is Fence fence2 && fence2.isGate.Value) { return fence2; } @@ -126,12 +126,12 @@ private static Fence GetConnectedGate(GameLocation location, Vector2 fenceLoc, F else if (type == FenceType.Vertical) { if (location.Objects.TryGetValue(fenceLoc + new Vector2(0, -1), out Object obj2) && - obj2 is Fence fence3 && fence3.isGate) + obj2 is Fence fence3 && fence3.isGate.Value) { return fence3; } if (location.Objects.TryGetValue(fenceLoc + new Vector2(0, 1), out obj2) && - obj2 is Fence fence4 && fence4.isGate) + obj2 is Fence fence4 && fence4.isGate.Value) { return fence4; } @@ -142,7 +142,7 @@ private static Fence GetConnectedGate(GameLocation location, Vector2 fenceLoc, F private static bool IsSingleFence(GameLocation location, Fence fence) { - return GetSurroundingObjects(location, fence.TileLocation).Any(f => !f.isGate); + return GetSurroundingObjects(location, fence.TileLocation).Any(f => !f.isGate.Value); } private static bool IsGatesSerial(GameLocation location, Vector2 fenceLoc, int dX, int dY, out int gateCount) @@ -158,7 +158,7 @@ private static bool IsGatesSerial(GameLocation location, Vector2 fenceLoc, int d return false; } - if (!fence.isGate) + if (!fence.isGate.Value) { break; } @@ -174,7 +174,7 @@ private static bool IsGatesSerial(GameLocation location, Vector2 fenceLoc, int d return false; } - if (!fence.isGate) + if (!fence.isGate.Value) { break; } diff --git a/JoysOfEfficiency/Automation/FlowerColorUnifier.cs b/GloryOfEfficiency/Automation/FlowerColorUnifier.cs similarity index 86% rename from JoysOfEfficiency/Automation/FlowerColorUnifier.cs rename to GloryOfEfficiency/Automation/FlowerColorUnifier.cs index 42bb047..85cf466 100644 --- a/JoysOfEfficiency/Automation/FlowerColorUnifier.cs +++ b/GloryOfEfficiency/Automation/FlowerColorUnifier.cs @@ -1,16 +1,17 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Menus; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Menus; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using StardewModdingAPI; using StardewValley; using StardewValley.TerrainFeatures; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { - using SVObject = Object; + using SVObject = StardewValley.Object; internal class FlowerIndex { @@ -39,7 +40,8 @@ public static void UnifyFlowerColors() continue; } Color oldColor = crop.tintColor.Value; - switch (crop.indexOfHarvest.Value) + int harvestIndex = Int32.Parse(crop.indexOfHarvest.Value); + switch (harvestIndex) { case FlowerIndex.Poppy: //Poppy @@ -62,7 +64,7 @@ public static void UnifyFlowerColors() crop.tintColor.Value = Config.FairyRoseColor; break; default: - Color? color = GetCustomizedFlowerColor(crop.indexOfHarvest.Value); + Color? color = GetCustomizedFlowerColor(harvestIndex); if (color != null) { crop.tintColor.Value = color.Value; @@ -70,7 +72,7 @@ public static void UnifyFlowerColors() } else { - continue; + continue; } } @@ -107,7 +109,7 @@ public static void ToggleFlowerColorUnification() { GameLocation loc = Game1.currentLocation; Vector2 tileLoc = Game1.currentCursorTile; - Dictionary hoeDirts = + Dictionary hoeDirts = loc.terrainFeatures.Pairs .Where(p => p.Value is HoeDirt) .ToDictionary(p => p.Key, p => p.Value as HoeDirt); @@ -135,32 +137,32 @@ public static void ToggleFlowerColorUnification() return; } - int index = crop.indexOfHarvest.Value; + int harvestIndex = Int32.Parse(crop.indexOfHarvest.Value); - if (IsVanillaFlower(index)) + if (IsVanillaFlower(harvestIndex)) { Util.ShowHudMessage(Translation.Get("flower.vanilla")); return; } - if (GetCustomizedFlowerColor(index) != null) + if (GetCustomizedFlowerColor(harvestIndex) != null) { // Unregister flower - Config.CustomizedFlowerColors.Remove(crop.indexOfHarvest.Value); + Config.CustomizedFlowerColors.Remove(harvestIndex); InstanceHolder.WriteConfig(); - Util.ShowHudMessage(string.Format(Translation.Get("flower.unregister"), Util.GetItemName(index))); + Util.ShowHudMessage(string.Format(Translation.Get("flower.unregister"), harvestIndex)); return; } // Show flower registration menu Game1.playSound("bigSelect"); - Game1.activeClickableMenu = new RegisterFlowerMenu(800, 640, crop.tintColor.Value, index, RegisterFlowerColor); + Game1.activeClickableMenu = new RegisterFlowerMenu(800, 640, crop.tintColor.Value, harvestIndex, RegisterFlowerColor); } private static void RegisterFlowerColor(int whichFlower, Color color) { Config.CustomizedFlowerColors.Add(whichFlower, color); - Util.ShowHudMessage(string.Format(Translation.Get("flower.register"), Util.GetItemName(whichFlower))); + Util.ShowHudMessage(string.Format(Translation.Get("flower.register"), whichFlower)); } } -} \ No newline at end of file +} diff --git a/GloryOfEfficiency/Automation/FoodAutomation.cs b/GloryOfEfficiency/Automation/FoodAutomation.cs new file mode 100644 index 0000000..a7ec712 --- /dev/null +++ b/GloryOfEfficiency/Automation/FoodAutomation.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using System.Linq; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; +using StardewModdingAPI; +using StardewValley; +using StardewValley.Tools; +using StardewModdingAPI.Events; +using StardewValley.GameData.Objects; +using SVObject = StardewValley.Object; + +namespace GloryOfEfficiency.Automation +{ + internal class FoodAutomation + { + private static Config Config => InstanceHolder.Config; + private static readonly Logger Logger = new Logger("FoodAutomation"); + private static HashSet _dontEat = new HashSet(); + + public static void TryToEatIfNeeded(Farmer player) + { + if (player.isEating || Game1.activeClickableMenu != null) + { + return; + } + + if (player.CurrentTool != null && player.CurrentTool is FishingRod rod) + { + if (rod.inUse() && !player.UsingTool) + { + return; + } + } + + if (!(player.Stamina <= player.MaxStamina * Config.StaminaToEatRatio) && + !(player.health <= player.maxHealth * Config.HealthToEatRatio)) + { + return; + } + + SVObject itemToEat = null; + foreach (SVObject item in player.Items.OfType()) + { + if (item.Edibility <= 0) + continue; + + //It's a edible item + if (itemToEat == null || + itemToEat.Edibility / itemToEat.salePrice() < item.Edibility / item.salePrice()) + { + //Found good edibility per price or just first food + itemToEat = item; + } + } + + if (itemToEat == null) + { + return; + } + + player.eatObject(itemToEat); + itemToEat.Stack--; + if (itemToEat.Stack == 0) + { + player.removeItemFromInventory(itemToEat); + } + } + + + // Don't Eat This mod copied and update here! Liberated from Pyrohead37. + public static void InitDontEat() + { + _dontEat.Clear(); + // public const int artisanGoodsCategory = -26; + // public const int ingredientsCategory = -25; + // public const int meatCategory = -14; + // public const int flowersCategory = -80; + // public const int FruitsCategory = -79; + // public const int VegetableCategory = -75; + // public const int FishCategory = -4; + // public const int EggCategory = -5; + // public const int MilkCategory = -6; + // public const int CookingCategory = -7; + // public const int inedible = -300; + // public const int GreensCategory = -81; + + // Go through all game objects and add any that are in our DontEatCategories first + foreach (KeyValuePair item in Game1.objectData) + { + string itemName = item.Value.Name; + int itemEdibility = item.Value.Edibility; + int itemCategory = item.Value.Category; + string categoryName = Object.GetCategoryDisplayName(itemCategory); + + if (itemEdibility == -300) { continue; } + if (Config.DontEatCategories.Contains(categoryName)) + { + _dontEat.Add(itemName); + Logger.Log($"Adding from Category [{item.Key}] {itemName} to the diet\t({categoryName})"); + } + } + + // Add individual items from DontEat list + foreach (var item in Config.DontEat) + { + _dontEat.Add(item); + Logger.Log($"Adding from DontEat {item} to the diet\t"); + } + + // REMOVE any items in the DoEat list! This must be last! + foreach (var item in Config.DoEat) + { + _dontEat.Remove(item); + Logger.Log($"REMOVING from DontEat {item}\t(DoEat exception)"); + } + + _dontEat.TrimExcess(); + } + + public static void ButtonPressed(object sender, ButtonPressedEventArgs e) + { + SVObject activePlayerItem = Game1.player.ActiveObject; + + if (Config.DontEatThat && Context.IsWorldReady && e.Button.IsActionButton() && activePlayerItem != null) + { + string itemName = activePlayerItem.DisplayName; + + // Logger.Log($"Testing item {itemName} for dontEatability"); + if (_dontEat.Contains(itemName)) + { + activePlayerItem.Edibility = -300; + Logger.Log($"Don't eat that {activePlayerItem.DisplayName}! Spoofing inedibility."); + } + } + } + } + + +} diff --git a/JoysOfEfficiency/Automation/HarvestAutomation.cs b/GloryOfEfficiency/Automation/HarvestAutomation.cs similarity index 80% rename from JoysOfEfficiency/Automation/HarvestAutomation.cs rename to GloryOfEfficiency/Automation/HarvestAutomation.cs index 67dea73..b6ef575 100644 --- a/JoysOfEfficiency/Automation/HarvestAutomation.cs +++ b/GloryOfEfficiency/Automation/HarvestAutomation.cs @@ -1,21 +1,19 @@ using System; using System.Collections.Generic; using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; -using StardewModdingAPI; using StardewValley; using StardewValley.Objects; using StardewValley.TerrainFeatures; using StardewValley.Tools; using SVObject = StardewValley.Object; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class HarvestAutomation { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; private static Config Config => InstanceHolder.Config; private static readonly Logger Logger = new Logger("HarvestAutomation"); @@ -54,6 +52,7 @@ public static void HarvestNearbyCrops(Farmer player) { Vector2 loc = kv.Key; HoeDirt dirt = kv.Value; + if (dirt.crop != null) Logger.Log($"Crop: {dirt.crop.indexOfHarvest} ** {dirt.crop.whichForageCrop}"); if (dirt.crop == null || !dirt.readyForHarvest()) { continue; @@ -69,9 +68,9 @@ public static void HarvestNearbyCrops(Farmer player) continue; } - if (dirt.crop.regrowAfterHarvest.Value == -1 || dirt.crop.forageCrop.Value) + if (dirt.crop.RegrowsAfterHarvest() == false || dirt.crop.forageCrop.Value) { - dirt.destroyCrop(loc, true, location); + dirt.destroyCrop(true); } } foreach (IndoorPot pot in Util.GetObjectsWithin(radius)) @@ -87,13 +86,23 @@ public static void HarvestNearbyCrops(Farmer player) continue; } - if (dirt.crop.regrowAfterHarvest.Value == -1 || dirt.crop.forageCrop.Value) + if (dirt.crop.RegrowsAfterHarvest() == false || dirt.crop.forageCrop.Value) { - dirt.destroyCrop(pot.TileLocation, true, location); + dirt.destroyCrop(true); } } } + public static void HarvestNearbySlimeBalls(Farmer player) + { + int radius = Config.AutoHarvestRadius; + + foreach (SVObject obj in Util.GetObjectsWithin(radius).Where(obj => obj.QualifiedItemId == "(BC)56")) + { + obj.checkForAction(player); + } + } + public static void WaterNearbyCrops() { WateringCan can = Util.FindToolFromInventory(Game1.player, InstanceHolder.Config.FindCanFromInventory); @@ -115,7 +124,7 @@ public static void WaterNearbyCrops() dirt.state.Value = 1; Game1.player.Stamina -= consume; - can.WaterLeft--; + if (!can.IsBottomless) can.WaterLeft--; watered = true; } foreach (IndoorPot pot in Util.GetObjectsWithin(InstanceHolder.Config.AutoWaterRadius)) @@ -130,7 +139,7 @@ public static void WaterNearbyCrops() dirt.state.Value = 1; pot.showNextIndex.Value = true; Game1.player.Stamina -= consume; - can.WaterLeft--; + if (!can.IsBottomless) can.WaterLeft--; watered = true; } } @@ -150,16 +159,13 @@ public static void ToggleBlacklistUnderCursor() return; if (dirt.crop == null) - { Util.ShowHudMessage("There is no crop under the cursor"); - } else { - string name = dirt.crop.forageCrop.Value ? Util.GetItemName(dirt.crop.whichForageCrop.Value) : Util.GetItemName(dirt.crop.indexOfHarvest.Value); + string cropID = dirt.crop.indexOfHarvest.Value; + string name = ItemRegistry.ResolveMetadata(cropID)?.GetParsedData().DisplayName; if (name == "") - { return; - } string text = ToggleBlackList(dirt.crop) ? $"{name} has been added to AutoHarvest exception" @@ -178,7 +184,7 @@ public static void DestroyNearDeadCrops(Farmer player) HoeDirt dirt = kv.Value; if (dirt.crop != null && dirt.crop.dead.Value) { - dirt.destroyCrop(loc, true, location); + dirt.destroyCrop(true); } } @@ -188,7 +194,7 @@ public static void DestroyNearDeadCrops(Farmer player) HoeDirt dirt = pot.hoeDirt.Value; if (dirt?.crop != null && dirt.crop.dead.Value) { - dirt.destroyCrop(loc, true, location); + dirt.destroyCrop(true); } } } @@ -198,17 +204,17 @@ public static void ShakeNearbyFruitedBush() int radius = InstanceHolder.Config.AutoShakeRadius; foreach (Bush bush in Game1.currentLocation.largeTerrainFeatures.OfType()) { - Vector2 loc = bush.tilePosition.Value; - Vector2 diff = loc - Game1.player.getTileLocation(); + Vector2 loc = bush.Tile; + Vector2 diff = loc - Game1.player.Tile; if (Math.Abs(diff.X) > radius || Math.Abs(diff.Y) > radius) continue; if (IsBushFruited(bush)) - bush.performUseAction(loc, Game1.currentLocation); + bush.performUseAction(loc); } } - public static void ShakeNearbyFruitedTree() + public static void ShakeNearbyFruitedTree() // RCB TODO... Broken for coconut trees [fine with bananas] { foreach (KeyValuePair kv in Util.GetFeaturesWithin(InstanceHolder.Config.AutoShakeRadius)) { @@ -225,44 +231,44 @@ public static void ShakeNearbyFruitedTree() } int num2; - switch (tree.treeType.Value) + switch (tree.treeType.Value) // treeType.Value is now a string! -RCB { - case 3: - num2 = 311; + case "3": + num2 = 311; // Pine Cone break; - case 1: - num2 = 309; + case "1": + num2 = 309; // Acorn break; - case 2: - num2 = 310; + case "2": + num2 = 310; // Maple Seed break; - case 6: - case 9: - num2 = 88; + case "6": + case "9": + num2 = 88; // Coconut break; default: num2 = -1; break; } - if (Game1.currentSeason.Equals("fall") && tree.treeType.Value == 2 && + if (Game1.currentSeason.Equals("fall") && tree.treeType.Value == "2" && Game1.dayOfMonth >= 14) { - num2 = 408; + num2 = 408; // Hazelnut } if (num2 != -1) - { - Reflection.GetMethod(tree, "shake").Invoke(loc, false, Game1.currentLocation); + { + tree.shake(loc, false); Logger.Log($@"Shook fruited tree @{loc}"); } } break; case FruitTree fruitTree: - if (fruitTree.growthStage.Value >= 4 && fruitTree.fruitsOnTree.Value > 0 && !fruitTree.stump.Value) + if (fruitTree.growthStage.Value >= 4 && fruitTree.fruit.Count > 0 && !fruitTree.stump.Value) { - fruitTree.shake(loc, false, Game1.currentLocation); + fruitTree.shake(loc, false); Logger.Log($@"Shook fruited tree @{loc}"); } break; @@ -279,20 +285,20 @@ public static void ShakeNearbyFruitedTree() private static bool IsBlackListed(Crop crop) { - int index = crop.forageCrop.Value ? crop.whichForageCrop.Value : crop.indexOfHarvest.Value; - return InstanceHolder.Config.HarvestException.Contains(index); + String cropName = crop.forageCrop.Value ? crop.whichForageCrop.Value : crop.indexOfHarvest.Value; + return InstanceHolder.Config.HarvestException.Contains(cropName); } private static bool ToggleBlackList(Crop crop) { - int index = crop.forageCrop.Value ? crop.whichForageCrop.Value : crop.indexOfHarvest.Value; + String cropName = crop.forageCrop.Value ? crop.whichForageCrop.Value : crop.indexOfHarvest.Value; if (IsBlackListed(crop)) { - InstanceHolder.Config.HarvestException.Remove(index); + InstanceHolder.Config.HarvestException.Remove(cropName); } else { - InstanceHolder.Config.HarvestException.Add(index); + InstanceHolder.Config.HarvestException.Add(cropName); } InstanceHolder.WriteConfig(); @@ -332,14 +338,14 @@ private static bool IsTeaBush(Bush bush) private static bool IsBerryBush(Bush bush) { - return bush.size.Value == Bush.mediumBush && !bush.townBush; + return bush.size.Value == Bush.mediumBush && !bush.townBush.Value; } private static bool IsBushFruited(Bush bush) { if (IsBerryBush(bush) || IsTeaBush(bush)) { - return bush.tileSheetOffset.Value == 1 && bush.inBloom(Game1.currentSeason, Game1.dayOfMonth); + return bush.tileSheetOffset.Value == 1 && bush.inBloom(); } return false; diff --git a/JoysOfEfficiency/Automation/InventoryAutomation.cs b/GloryOfEfficiency/Automation/InventoryAutomation.cs similarity index 86% rename from JoysOfEfficiency/Automation/InventoryAutomation.cs rename to GloryOfEfficiency/Automation/InventoryAutomation.cs index f24702c..86cbe02 100644 --- a/JoysOfEfficiency/Automation/InventoryAutomation.cs +++ b/GloryOfEfficiency/Automation/InventoryAutomation.cs @@ -1,16 +1,12 @@ -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Huds; -using JoysOfEfficiency.Utils; -using StardewModdingAPI; +using GloryOfEfficiency.Huds; +using GloryOfEfficiency.Utils; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class InventoryAutomation { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; - private static readonly Logger Logger = new Logger("InventoryAutomation"); public static void LootAllAcceptableItems(ItemGrabMenu menu, bool skipCheck = false) @@ -81,7 +77,7 @@ public static void TryCloseItemGrabMenu(ItemGrabMenu menu) return; } - if (menu.context is Event && GetEssential(menu)) + if (menu.context is Event && menu.essential) { // You should not emergency close in events (it may stop the dialogue). return; @@ -96,10 +92,5 @@ public static void TryCloseItemGrabMenu(ItemGrabMenu menu) menu.exitThisMenu(); } - - private static bool GetEssential(ItemGrabMenu menu) - { - return Reflection.GetField(menu, "essential").GetValue(); - } } } diff --git a/GloryOfEfficiency/Automation/MachineOperator.cs b/GloryOfEfficiency/Automation/MachineOperator.cs new file mode 100644 index 0000000..4585805 --- /dev/null +++ b/GloryOfEfficiency/Automation/MachineOperator.cs @@ -0,0 +1,148 @@ +using System.Linq; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; +using Microsoft.Xna.Framework; +using StardewValley; +using StardewValley.Locations; +using StardewValley.Objects; +using SVObject = StardewValley.Object; +using static StardewValley.Game1; + +namespace GloryOfEfficiency.Automation +{ + internal class MachineOperator + { + private static readonly Logger Logger = new Logger("MachineOperator"); + + public static void DepositIngredientsToMachines() + { + Farmer player = Game1.player; + if (player.CurrentItem == null || !(player.CurrentItem is SVObject item)) + { + return; + } + + foreach (SVObject obj in Util.GetObjectsWithin(InstanceHolder.Config.MachineRadius).Where(IsObjectMachine)) + { + Vector2 loc = Util.GetLocationOf(currentLocation, obj); + if (obj.heldObject.Value != null) + continue; + + if (obj.Name == "Keg" && item.ParentSheetIndex == 433 && item.Stack < 5) + { + // You don't have enough beans. + Logger.Log($"Trying to deposit {item.Name} into KEG: {obj.Name}. Not enough beans!"); + return; + } + + bool accepted = obj.Name == "Furnace" ? CanFurnaceAcceptItem(item, player) : Utility.isThereAnObjectHereWhichAcceptsThisItem(currentLocation, item, (int)loc.X * tileSize, (int)loc.Y * tileSize); + Logger.Log($"Trying to deposit ({accepted}) {item.Name} into machine: {obj.Name}"); + if (obj is Cask) + { + if (ModEntry.IsCoGOn || ModEntry.IsCaOn) + { + if (obj.performObjectDropInAction(item, true, player)) + { + obj.heldObject.Value = null; + accepted = true; + } + } + else if (currentLocation is not Cellar && accepted) + { + accepted = false; + } + } + else if (obj.Name == "Crab Pot") + { + if (item.Name == "Bait" || item.Name == "Magic Bait") + { + accepted = true; + Logger.Log($"\tCrab Pot and {item.Name} are now ACCEPTED."); + } + } + else if (obj.Name == "Seed Maker" && InstanceHolder.Config.AutoDepositSeedMaker == false) + { + continue; + } + + if (!accepted) + continue; + + // performObjectDropInAction but only if it's currently empty + if (obj.performObjectDropInAction(item, false, player, true)) + { + player.reduceActiveItemByOne(); + Logger.Log($"Item {obj} MANUALLY consuming {item.Name}"); + } else { + Logger.Log($"Item {obj} should have already consumed {item.Name}"); + } + Logger.Log($"DONE dropping {item.Name} into {obj}."); + + return; + } + } + + public static void PullMachineResult() + { + Farmer player = Game1.player; + foreach (SVObject obj in Util.GetObjectsWithin(InstanceHolder.Config.MachineRadius).Where(IsObjectMachine)) + { + // Nothing in the machine... + if (obj.heldObject.Value == null) + { + continue; + } + else if (!obj.readyForHarvest.Value) + { + Logger.Log($"Time until {obj.Name} ready for collecting item {obj.heldObject.Value.Name}: {obj.MinutesUntilReady} game minutes."); + continue; + } + + Item item = obj.heldObject.Value; + if (player.couldInventoryAcceptThisItem(item)) + obj.checkForAction(player); + } + } + + private static bool CanFurnaceAcceptItem(Item item, Farmer player) + { + Logger.Log($"{player.Items.ContainsId(Object.coalQID)} ** {item.Stack} ** {item.ParentSheetIndex}"); + + // Minimum of one coal in inventory + if (! player.Items.ContainsId(Object.coalQID, 1)) + return false; + + switch (item.Name) + { + // One item per coal... + case "Clay": + case "Quartz": + case "Fire Quartz": + break; + + // Five items per coal... + case "Copper Ore": + case "Iron Ore": + case "Gold Ore": + case "Iridium Ore": + case "Radioactive Ore": + if (item.Stack < 5) + return false; + break; + + default: + return false; + } + return true; + } + + private static bool IsObjectMachine(SVObject obj) + { + if (InstanceHolder.Config.MachineTypes.Contains(obj.Name)) + { + return true; + } + return false; + } + } +} diff --git a/JoysOfEfficiency/Automation/MailAutomation.cs b/GloryOfEfficiency/Automation/MailAutomation.cs similarity index 85% rename from JoysOfEfficiency/Automation/MailAutomation.cs rename to GloryOfEfficiency/Automation/MailAutomation.cs index b0ba891..b9ff942 100644 --- a/JoysOfEfficiency/Automation/MailAutomation.cs +++ b/GloryOfEfficiency/Automation/MailAutomation.cs @@ -1,22 +1,19 @@ -using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; -using StardewModdingAPI; +using System; +using System.Linq; +using GloryOfEfficiency.Utils; using StardewValley; using StardewValley.Menus; using StardewValley.Quests; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class MailAutomation { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; - private static readonly Logger Logger = new Logger("MailAutomation"); public static void CollectMailAttachmentsAndQuests(LetterViewerMenu menu) { - int questId = menu.questID; + String questId = menu.questID; if (menu.itemsLeftToGrab()) { @@ -43,7 +40,7 @@ public static void CollectMailAttachmentsAndQuests(LetterViewerMenu menu) } } - if (questId == -1) + if (questId == null) { return; } @@ -51,7 +48,7 @@ public static void CollectMailAttachmentsAndQuests(LetterViewerMenu menu) Logger.Log($"You started Quest: '{Quest.getQuestFromId(questId).questTitle}'."); Game1.player.addQuest(questId); Game1.playSound("newArtifact"); - menu.questID = -1; + menu.questID = null; } private static bool CanPlayerAcceptsItemPartially(Item item) diff --git a/GloryOfEfficiency/Automation/TrashCanScavenger.cs b/GloryOfEfficiency/Automation/TrashCanScavenger.cs new file mode 100644 index 0000000..b1d7c7a --- /dev/null +++ b/GloryOfEfficiency/Automation/TrashCanScavenger.cs @@ -0,0 +1,41 @@ +using GloryOfEfficiency.Core; +using Microsoft.Xna.Framework; +using StardewValley; +using StardewValley.Locations; +using xTile.Layers; + +namespace GloryOfEfficiency.Automation +{ + internal class TrashCanScavenger + { + private static Config Config => InstanceHolder.Config; + + public static void ScavengeTrashCan() + { + if (!(Game1.currentLocation is Town town)) + { + return; + } + + Farmer player = Game1.player; + int radius = InstanceHolder.Config.BalancedMode ? 1 : InstanceHolder.Config.ScavengingRadius; + Layer layer = Game1.currentLocation.Map.GetLayer("Buildings"); + Point currPos = player.TilePoint; + int ox = currPos.X; + int oy = currPos.Y; + for (int dy = -radius; dy <= radius; dy++) + { + for (int dx = -radius; dx <= radius; dx++) + { + int x = ox + dx, y = oy + dy; + + if (layer.Tiles[x, y]?.TileIndex == 78) + { + string whichGarbage = Game1.currentLocation.doesTileHaveProperty(x, y, "Action", "Buildings"); + town.CheckGarbage(whichGarbage, new Vector2(x, y), Game1.player, true, Config.GarbageDisgustsNPCs); + } + } + } + } + } +} diff --git a/JoysOfEfficiency/Automation/WateringCanRefiller.cs b/GloryOfEfficiency/Automation/WateringCanRefiller.cs similarity index 82% rename from JoysOfEfficiency/Automation/WateringCanRefiller.cs rename to GloryOfEfficiency/Automation/WateringCanRefiller.cs index cc9d5e4..00b5feb 100644 --- a/JoysOfEfficiency/Automation/WateringCanRefiller.cs +++ b/GloryOfEfficiency/Automation/WateringCanRefiller.cs @@ -1,9 +1,9 @@ -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using StardewValley; using StardewValley.Tools; -namespace JoysOfEfficiency.Automation +namespace GloryOfEfficiency.Automation { internal class WateringCanRefiller { @@ -12,7 +12,7 @@ public static void RefillWateringCan() { WateringCan can = Util.FindToolFromInventory(Config.FindCanFromInventory); if (can == null || can.WaterLeft >= Util.GetMaxCan(can) || - !Util.IsThereAnyWaterNear(Game1.player.currentLocation, Game1.player.getTileLocation())) + !Util.IsThereAnyWaterNear(Game1.player.currentLocation, Game1.player.Tile)) { return; } diff --git a/JoysOfEfficiency/Configs/ConfigCustomAnimalTool.cs b/GloryOfEfficiency/Configs/ConfigCustomAnimalTool.cs similarity index 95% rename from JoysOfEfficiency/Configs/ConfigCustomAnimalTool.cs rename to GloryOfEfficiency/Configs/ConfigCustomAnimalTool.cs index 0b65388..7663d9d 100644 --- a/JoysOfEfficiency/Configs/ConfigCustomAnimalTool.cs +++ b/GloryOfEfficiency/Configs/ConfigCustomAnimalTool.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using StardewValley; using StardewValley.Tools; -namespace JoysOfEfficiency.Configs +namespace GloryOfEfficiency.Configs { class ConfigCustomAnimalTool { diff --git a/JoysOfEfficiency/Configs/CustomAnimalTool.cs b/GloryOfEfficiency/Configs/CustomAnimalTool.cs similarity index 90% rename from JoysOfEfficiency/Configs/CustomAnimalTool.cs rename to GloryOfEfficiency/Configs/CustomAnimalTool.cs index 76067bb..95850aa 100644 --- a/JoysOfEfficiency/Configs/CustomAnimalTool.cs +++ b/GloryOfEfficiency/Configs/CustomAnimalTool.cs @@ -1,4 +1,4 @@ -namespace JoysOfEfficiency.Configs +namespace GloryOfEfficiency.Configs { class CustomAnimalTool { diff --git a/JoysOfEfficiency/Core/Config.cs b/GloryOfEfficiency/Core/Config.cs similarity index 63% rename from JoysOfEfficiency/Core/Config.cs rename to GloryOfEfficiency/Core/Config.cs index c1602c1..9fb47d9 100644 --- a/JoysOfEfficiency/Core/Config.cs +++ b/GloryOfEfficiency/Core/Config.cs @@ -1,13 +1,15 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using StardewModdingAPI; -namespace JoysOfEfficiency.Core +namespace GloryOfEfficiency.Core { internal class Config { - + public bool BalancedMode { get; set; } = true; + public uint RunEveryNthTick { get; set; } = 15; // If BalancedMode is False, then run every 15th tick by default (0.25 seconds) public bool SafeMode { get; set; } = false; public bool MineInfoGui { get; set; } = true; @@ -37,6 +39,9 @@ internal class Config public SButton ToggleAfkFishing { get; set; } = SButton.End; public bool FishingInfo { get; set; } = true; + public bool FishingTackleInfo { get; set; } = false; + public bool TackleBoxAttach { get; set; } = false; + public Point TackleBoxCoordinates { get; set; } = new Point(40, 500); public bool AutoGate { get; set; } = true; @@ -44,10 +49,40 @@ internal class Config public float StaminaToEatRatio { get; set; } = 0.2f; public float HealthToEatRatio { get; set; } = 0.2f; + + public bool DontEatThat { get; set; } = false; + + public List DontEatCategories { get; set; } = new List() + { + "Artisan Goods", + "Animal Product", + "Fish", + "Crop", + "Vegetable", + "Flower", + "Harmful", + }; + public List DontEat { get; set; } = new List() + { + "Holly", + "Oil", + "Red Mushroom", + "Sap", + "Truffle", + }; + public List DoEat { get; set; } = new List() + { + "Mayonnaise", + "Beer", + "Green Tea", + }; + + public bool AutoHarvest { get; set; } = true; + public bool AutoHarvestSlimeBalls { get; set; } = true; public int AutoHarvestRadius { get; set; } = 1; public bool ProtectNectarProducingFlower { get; set; } = true; - public List HarvestException { get; set; } = new List(); + public HashSet HarvestException { get; set; } = new HashSet(); public SButton ButtonToggleBlackList { get; set; } = Keys.F2.ToSButton(); public bool AutoDestroyDeadCrops { get; set; } = true; @@ -64,15 +99,54 @@ internal class Config public bool AutoShakeFruitedPlants { get; set; } = true; public int AutoShakeRadius { get; set; } = 1; - public bool BalancedMode { get; set; } = true; public bool AutoDepositIngredient { get; set; } = false; + public bool AutoDepositSeedMaker { get; set; } = false; public bool AutoPullMachineResult { get; set; } = true; public int MachineRadius { get; set; } = 1; + public HashSet MachineTypes { get; set; } = new HashSet() + { + "Bait Maker", + "Bee House", + "Bone Mill", + "Cask", + "Charcoal Kiln", + "Cheese Press", + "Coffee Maker", + "Crab Pot", + "Crystalarium", + "Dehydrator", + "Deluxe Worm Bin", + "Fish Smoker", + "Furnace", + "Heavy Furnace", + "Heavy Tapper", + "Incubator", + "Keg", + "Loom", + "Lightning Rod", + "Mayonnaise Machine", + "Mushroom Box", + "Mushroom Log", + "Oil Maker", + "Preserves Jar", + "Recycling Machine", + "Seed Maker", + "Sewing Machine", + "Slime Egg-Press", + "Slime Incubator", + "Statue Of Endless Fortune", + "Statue Of Perfection", + "Tapper", + "Wood Chipper", + "Worm Bin", + }; + //Fishing Probabilities public bool FishingProbabilitiesInfo { get; set; } = false; - public Point ProbBoxCoordinates { get; set; } = new Point(100, 400); + public int ProbBoxMaxFish { get; set; } = 10; + public Point ProbBoxCoordinates { get; set; } = new Point(40, 500); public bool MorePreciseProbabilities { get; set; } = true; public int TrialOfExamine { get; set; } = 10; @@ -100,6 +174,7 @@ internal class Config public int PauseNotificationY { get; set; } = 700; public bool AutoPickUpTrash { get; set; } = false; + public bool GarbageDisgustsNPCs { get; set; } = true; public int ScavengingRadius { get; set; } = 2; public bool AutoShearingAndMilking { get; set; } = true; @@ -111,5 +186,10 @@ internal class Config public bool ChopTwigs { get; set; } = false; public bool DisableConfigLimitation { get; set; } = false; + + public int WindowWidth { get; set; } = 1280; + public int WindowHeight { get; set; } = 800; + public int WindowX { get; set; } = 950; + public int WindowY { get; set; } = 300; } } diff --git a/JoysOfEfficiency/Core/ConfigLimitation.cs b/GloryOfEfficiency/Core/ConfigLimitation.cs similarity index 96% rename from JoysOfEfficiency/Core/ConfigLimitation.cs rename to GloryOfEfficiency/Core/ConfigLimitation.cs index 0cb8e14..2700218 100644 --- a/JoysOfEfficiency/Core/ConfigLimitation.cs +++ b/GloryOfEfficiency/Core/ConfigLimitation.cs @@ -1,6 +1,6 @@ -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Utils; -namespace JoysOfEfficiency.Core +namespace GloryOfEfficiency.Core { internal class ConfigLimitation { diff --git a/JoysOfEfficiency/Core/InstanceHolder.cs b/GloryOfEfficiency/Core/InstanceHolder.cs similarity index 74% rename from JoysOfEfficiency/Core/InstanceHolder.cs rename to GloryOfEfficiency/Core/InstanceHolder.cs index 8931bb2..da6a157 100644 --- a/JoysOfEfficiency/Core/InstanceHolder.cs +++ b/GloryOfEfficiency/Core/InstanceHolder.cs @@ -1,8 +1,8 @@ -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Utils; using StardewModdingAPI; using StardewValley; -namespace JoysOfEfficiency.Core +namespace GloryOfEfficiency.Core { /// /// This class holds mod and config instance and exposes some useful methods. @@ -14,15 +14,14 @@ internal class InstanceHolder public static Config Config { get; private set; } private static IModHelper Helper => ModInstance.Helper; public static ITranslationHelper Translation => Helper.Translation; - public static IReflectionHelper Reflection => Helper.Reflection; - public static Multiplayer Multiplayer => Reflection.GetField(typeof(Game1), "multiplayer").GetValue(); + public static Multiplayer Multiplayer => Game1.Multiplayer; - public static InputState Input => Reflection.GetField(typeof(Game1), "input").GetValue(); + public static InputState Input => Game1.input; public static CustomAnimalConfigHolder CustomAnimalTool; /// - /// Sets mod's entry point and configuration instance. + /// Sets mod's entry point and configuration instance. /// /// the mod instance /// the configuration instance @@ -32,7 +31,7 @@ public static void Init(ModEntry modInstance) Config = LoadConfig(); CustomAnimalTool = new CustomAnimalConfigHolder(modInstance.GetFilePath("customAnimalTools.json")); } - + /// /// Writes settings to '(ModFolder)/config.json'. /// diff --git a/JoysOfEfficiency/Core/ModEntry.cs b/GloryOfEfficiency/Core/ModEntry.cs similarity index 57% rename from JoysOfEfficiency/Core/ModEntry.cs rename to GloryOfEfficiency/Core/ModEntry.cs index db5aaa5..cc9b3c7 100644 --- a/JoysOfEfficiency/Core/ModEntry.cs +++ b/GloryOfEfficiency/Core/ModEntry.cs @@ -1,17 +1,19 @@ using System.IO; -using JoysOfEfficiency.EventHandler; -using JoysOfEfficiency.Harmony; -using JoysOfEfficiency.Huds; -using JoysOfEfficiency.ModCheckers; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Automation; +using GloryOfEfficiency.EventHandler; +using GloryOfEfficiency.Harmony; +using GloryOfEfficiency.Huds; +using GloryOfEfficiency.ModCheckers; +using GloryOfEfficiency.Utils; +using Microsoft.Xna.Framework; using StardewModdingAPI; +using StardewModdingAPI.Events; using StardewValley; -namespace JoysOfEfficiency.Core +namespace GloryOfEfficiency.Core { using Player = Farmer; - /// /// This class is a representation of the mod itself. /// @@ -39,14 +41,13 @@ public override void Entry(IModHelper helper) // Register events. EventHolder.RegisterEvents(Helper.Events); + // Limit config values. + ConfigLimitation.LimitConfigValues(); // Registration commands. Helper.ConsoleCommands.Add("joedebug", "Debug command for JoE", OnDebugCommand); Helper.ConsoleCommands.Add("joerelcon", "Reloading config command for JoE", OnReloadConfigCommand); - - - // Limit config values. - ConfigLimitation.LimitConfigValues(); + Helper.Events.GameLoop.GameLaunched += OnGameLaunched; // Check mod compatibilities. if(ModChecker.IsCoGLoaded(helper)) @@ -72,6 +73,13 @@ public override void Entry(IModHelper helper) } helper.WriteConfig(Conf); + + if (Conf.DontEatThat) + { + Logger.Log($"Don't Eat That(tm) is enabled!"); + Helper.Events.Input.ButtonPressed += FoodAutomation.ButtonPressed; + } + MineIcons.Init(helper); } @@ -79,13 +87,37 @@ private static void OnReloadConfigCommand(string name, string[] args) { // Loads configuration from file. InstanceHolder.LoadConfig(); + if (Conf.DontEatThat) + { + Logger.Log($"Don't Eat That(tm) is enabled!"); + FoodAutomation.InitDontEat(); + } Logger.Log("Reloaded JoE's config."); } + private static void OnGameLaunched(object sender, GameLaunchedEventArgs e) + { + if (Conf.DontEatThat) + { + Logger.Log($"Don't Eat That(tm) is enabled!"); + FoodAutomation.InitDontEat(); + } + + Game1.graphics.PreferredBackBufferWidth = Conf.WindowWidth; + Game1.graphics.PreferredBackBufferHeight = Conf.WindowHeight; + var viewport = Game1.graphics.GraphicsDevice.Viewport; + viewport.Width = Conf.WindowWidth; + viewport.Height = Conf.WindowHeight; +// viewport.X = Conf.WindowX; // Hackswell: seems to do nothing +// viewport.Y = Conf.WindowY; // Hackswell: seems to do nothing +// viewport.Bounds = new Rectangle(new Point(Conf.WindowX, Conf.WindowY), new Point(Conf.WindowWidth, Conf.WindowHeight)); // Hackswell: seems to do nothing + GameRunner.instance.Window.Position = new Point(Conf.WindowX, Conf.WindowY); // Hackswell: seems to do nothing + Game1.graphics.ApplyChanges(); + } + private static void OnDebugCommand(string name, string[] args) { DebugMode = !DebugMode; - } public string GetFilePath(string fileName) diff --git a/GloryOfEfficiency/EventHandler/ArtifactSpotDigger.cs b/GloryOfEfficiency/EventHandler/ArtifactSpotDigger.cs new file mode 100644 index 0000000..260765c --- /dev/null +++ b/GloryOfEfficiency/EventHandler/ArtifactSpotDigger.cs @@ -0,0 +1,69 @@ +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; +using Microsoft.Xna.Framework; +using StardewValley; +using StardewValley.TerrainFeatures; +using StardewValley.Tools; + +namespace GloryOfEfficiency.EventHandler +{ + internal class ArtifactSpotDigger + { + private static Config Config => InstanceHolder.Config; + private static readonly Logger Logger = new Logger("ArtifactSpotDigger"); + private static Farmer player = Game1.player; + + public static void DigNearbyArtifactSpots() + { + int radius = Config.AutoDigRadius; + Hoe hoe = Util.FindToolFromInventory(player, InstanceHolder.Config.FindHoeFromInventory); + if (hoe == null) + { + return; + } + + bool flag = false; + GameLocation location = player.currentLocation; + for (int i = -radius; i <= radius; i++) + { + for (int j = -radius; j <= radius; j++) + { + Point currPos = player.TilePoint; + int x = currPos.X + i; + int y = currPos.Y + j; + Vector2 loc = new Vector2(x, y); + if (!location.Objects.ContainsKey(loc) || location.isTileHoeDirt(loc)) + { + continue; + } + + if (location.Objects[loc].name == "Artifact Spot") + { + Logger.Log($"ArtifactSpot: {location.Objects[loc].name} at [{loc.X},{loc.Y}]"); + + location.digUpArtifactSpot(x, y, player); + location.Objects.Remove(loc); + location.terrainFeatures.Add(loc, new HoeDirt()); + flag = true; + } + else if (location.Objects[loc].name == "Seed Spot") + { + Logger.Log($"SeedSpot: {location.Objects[loc].name} at [{loc.X},{loc.Y}]"); + + // Liberated this from Pathoschild's "TractorMod" + player.lastClick = (loc * Game1.tileSize) + new Vector2(Game1.tileSize / 2f); + hoe.swingTicker++; + hoe.DoFunction(location, (int)player.lastClick.X, (int)player.lastClick.Y, 0, player); + flag = true; + } + } + } + + if (flag) + { + Game1.playSound("hoeHit"); + } + } + + } +} diff --git a/JoysOfEfficiency/EventHandler/EventHolder.cs b/GloryOfEfficiency/EventHandler/EventHolder.cs similarity index 93% rename from JoysOfEfficiency/EventHandler/EventHolder.cs rename to GloryOfEfficiency/EventHandler/EventHolder.cs index 71342a3..13debc7 100644 --- a/JoysOfEfficiency/EventHandler/EventHolder.cs +++ b/GloryOfEfficiency/EventHandler/EventHolder.cs @@ -1,7 +1,7 @@ -using JoysOfEfficiency.Huds; +using GloryOfEfficiency.Huds; using StardewModdingAPI.Events; -namespace JoysOfEfficiency.EventHandler +namespace GloryOfEfficiency.EventHandler { internal class EventHolder { diff --git a/JoysOfEfficiency/EventHandler/GraphicsEvents.cs b/GloryOfEfficiency/EventHandler/GraphicsEvents.cs similarity index 84% rename from JoysOfEfficiency/EventHandler/GraphicsEvents.cs rename to GloryOfEfficiency/EventHandler/GraphicsEvents.cs index 0548098..aa71ed9 100644 --- a/JoysOfEfficiency/EventHandler/GraphicsEvents.cs +++ b/GloryOfEfficiency/EventHandler/GraphicsEvents.cs @@ -1,14 +1,14 @@ -using JoysOfEfficiency.Automation; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Huds; -using JoysOfEfficiency.Misc; +using GloryOfEfficiency.Automation; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Huds; +using GloryOfEfficiency.Misc; using StardewModdingAPI.Events; using StardewValley; using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Tools; -namespace JoysOfEfficiency.EventHandler +namespace GloryOfEfficiency.EventHandler { internal class GraphicsEvents { @@ -24,7 +24,7 @@ public void OnRenderHud(object sender, RenderingHudEventArgs args) { GiftInformationTooltip.DrawTooltip(); } - if (Conf.FishingProbabilitiesInfo && Game1.player.CurrentTool is FishingRod rod && rod.isFishing) + if (Game1.player.CurrentTool is FishingRod rod && rod.isFishing) { FishingProbabilitiesBox.PrintFishingInfo(); } diff --git a/JoysOfEfficiency/EventHandler/InputEvents.cs b/GloryOfEfficiency/EventHandler/InputEvents.cs similarity index 88% rename from JoysOfEfficiency/EventHandler/InputEvents.cs rename to GloryOfEfficiency/EventHandler/InputEvents.cs index ae7d0b6..d2fb592 100644 --- a/JoysOfEfficiency/EventHandler/InputEvents.cs +++ b/GloryOfEfficiency/EventHandler/InputEvents.cs @@ -1,11 +1,11 @@ -using JoysOfEfficiency.Automation; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Menus; +using GloryOfEfficiency.Automation; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Menus; using StardewModdingAPI; using StardewModdingAPI.Events; using StardewValley; -namespace JoysOfEfficiency.EventHandler +namespace GloryOfEfficiency.EventHandler { internal class InputEvents { diff --git a/JoysOfEfficiency/EventHandler/MenuEvents.cs b/GloryOfEfficiency/EventHandler/MenuEvents.cs similarity index 85% rename from JoysOfEfficiency/EventHandler/MenuEvents.cs rename to GloryOfEfficiency/EventHandler/MenuEvents.cs index a6f5bcf..becae96 100644 --- a/JoysOfEfficiency/EventHandler/MenuEvents.cs +++ b/GloryOfEfficiency/EventHandler/MenuEvents.cs @@ -1,9 +1,9 @@ -using JoysOfEfficiency.Automation; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Automation; +using GloryOfEfficiency.Core; using StardewModdingAPI.Events; using StardewValley.Menus; -namespace JoysOfEfficiency.EventHandler +namespace GloryOfEfficiency.EventHandler { internal class MenuEvents { diff --git a/JoysOfEfficiency/EventHandler/SaveEvents.cs b/GloryOfEfficiency/EventHandler/SaveEvents.cs similarity index 85% rename from JoysOfEfficiency/EventHandler/SaveEvents.cs rename to GloryOfEfficiency/EventHandler/SaveEvents.cs index 267e570..af757da 100644 --- a/JoysOfEfficiency/EventHandler/SaveEvents.cs +++ b/GloryOfEfficiency/EventHandler/SaveEvents.cs @@ -1,10 +1,10 @@ using System; -using JoysOfEfficiency.Automation; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Misc; +using GloryOfEfficiency.Automation; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Misc; using StardewModdingAPI; -namespace JoysOfEfficiency.EventHandler +namespace GloryOfEfficiency.EventHandler { internal class SaveEvents { diff --git a/JoysOfEfficiency/EventHandler/UpdateEvents.cs b/GloryOfEfficiency/EventHandler/UpdateEvents.cs similarity index 76% rename from JoysOfEfficiency/EventHandler/UpdateEvents.cs rename to GloryOfEfficiency/EventHandler/UpdateEvents.cs index 903c2f2..a79ffc4 100644 --- a/JoysOfEfficiency/EventHandler/UpdateEvents.cs +++ b/GloryOfEfficiency/EventHandler/UpdateEvents.cs @@ -1,9 +1,9 @@ using System; -using JoysOfEfficiency.Automation; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Huds; -using JoysOfEfficiency.Misc; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Automation; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Huds; +using GloryOfEfficiency.Misc; +using GloryOfEfficiency.Utils; using StardewModdingAPI; using StardewModdingAPI.Events; using StardewValley; @@ -11,25 +11,27 @@ using StardewValley.Menus; using StardewValley.Tools; -namespace JoysOfEfficiency.EventHandler +namespace GloryOfEfficiency.EventHandler { internal class UpdateEvents { public static bool DayEnded { get; set; } - private int _ticks; - - private static Config Conf => InstanceHolder.Config; private static readonly Logger Logger = new Logger("UpdateEvent"); + // Run Every Nth tick... unless balanced mode, then it's 60 ticks (1 second) + private uint NthTick = (Conf.BalancedMode) ? 60 : Conf.RunEveryNthTick; + + // This updates every GameTick (approx 60x / second) public void OnGameUpdateEvent(object sender, UpdateTickedEventArgs args) { OnEveryUpdate(); - if (args.IsMultipleOf(8)) + if (args.IsMultipleOf(NthTick)) { - OnGameEighthUpdate(); + OnGameNthTickUpdate(); + NthTick = (Conf.BalancedMode) ? 60 : Conf.RunEveryNthTick; // Update in case config has changed... } } @@ -39,7 +41,7 @@ public void OnEveryUpdate() { return; } - + IdlePause.OnTickUpdate(); Farmer player = Game1.player; @@ -51,26 +53,24 @@ public void OnEveryUpdate() if (player.CurrentTool is FishingRod rod) { FishingProbabilitiesBox.UpdateProbabilities(rod); - AutoFisher.AfkFishing(); + if (Conf.AutoReelRod) + { + AutoFisher.AutoReelRod(); + } + if (Conf.CloseTreasureWhenAllLooted && Game1.activeClickableMenu is ItemGrabMenu menu) + { + InventoryAutomation.TryCloseItemGrabMenu(menu); + } } GiftInformationTooltip.UpdateTooltip(); } - private void OnGameEighthUpdate() + // Every Nth tick. Default is 15. 60 == 1.00 seconds; 15 == 0.25 seconds; 6 == 0.10 seconds. + private void OnGameNthTickUpdate() { - if (Game1.currentGameTime == null) - { - return; - } - - if (Conf.CloseTreasureWhenAllLooted && Game1.activeClickableMenu is ItemGrabMenu menu) - { - InventoryAutomation.TryCloseItemGrabMenu(menu); - } - - if (!Context.IsWorldReady || !Context.IsPlayerFree) + if (Game1.currentGameTime == null || !Context.IsWorldReady || !Context.IsPlayerFree) { return; } @@ -79,33 +79,20 @@ private void OnGameEighthUpdate() GameLocation location = Game1.currentLocation; try { - if (Conf.AutoReelRod) - { - AutoFisher.AutoReelRod(); - } - if (Game1.currentLocation is MineShaft shaft) + if (Game1.currentLocation is MineShaft { isFallingDownShaft: true }) { - bool isFallingDownShaft = InstanceHolder.Reflection.GetField(shaft, "isFallingDownShaft").GetValue(); - if (isFallingDownShaft) - { - return; - } + return; } if (!Context.CanPlayerMove) { return; } + + FarmCleaner.OnNthTickUpdate(); if (Conf.UnifyFlowerColors) { FlowerColorUnifier.UnifyFlowerColors(); } - - _ticks = (_ticks + 1) % 8; - if (Conf.BalancedMode && _ticks != 0) - { - return; - } - FarmCleaner.OnEighthUpdate(); if (Conf.AutoEat) { FoodAutomation.TryToEatIfNeeded(player); @@ -122,7 +109,6 @@ private void OnGameEighthUpdate() { AnimalAutomation.PetNearbyAnimals(); } - if (Conf.AutoShearingAndMilking) { AnimalAutomation.ShearingAndMilking(player); @@ -139,6 +125,10 @@ private void OnGameEighthUpdate() { HarvestAutomation.HarvestNearbyCrops(player); } + if (Conf.AutoHarvestSlimeBalls) + { + HarvestAutomation.HarvestNearbySlimeBalls(player); + } if (Conf.AutoDestroyDeadCrops) { HarvestAutomation.DestroyNearDeadCrops(player); diff --git a/JoysOfEfficiency/FeaturesAndConfigs.md b/GloryOfEfficiency/FeaturesAndConfigs.md similarity index 54% rename from JoysOfEfficiency/FeaturesAndConfigs.md rename to GloryOfEfficiency/FeaturesAndConfigs.md index c74c72a..b8cec41 100644 --- a/JoysOfEfficiency/FeaturesAndConfigs.md +++ b/GloryOfEfficiency/FeaturesAndConfigs.md @@ -4,15 +4,12 @@ This is a list of features and configs available in [Joys of Efficiency (JoE)](h Config description will be like: - Name("Category Tab in config menu", Type, default value, [minimum or maximum value if its type is int or float]) - "discription of the config". - "Category Tab in config menu" is one of following: "Automation", "UIs", "Cheats", "Misc", "Controls", and "Not on menu". # Features - ## Safe Mode If Safe Mode is enabled, JoE won't patch the game itself, so it's much safer. @@ -28,110 +25,78 @@ You can open mod configuration menu when specified key(Default:R). You can't disable this feature because it's a core feature. **[CONFIG]** - - - KeyShowMenu("Controls", SButton, default:"R") - The key to open config menu. - - - FilterBackgroundInMenu("UIs", bool, default:true) - When config menu is opened, outside of it will be darker like inventory menu. - - ShowMousePositionWhenAssigningLocation("UIs", bool, default:true) - When assigning coordinates of window, shows mouse cursor's position. + ## Balanced Mode -Did you thought following utilities are a bit cheaty? +Did you think the following utilities are a bit cheaty? -This utility lets them not to be executed so often(almost 1 executing per seconds), and -automation radius will be 1 tile. +This utility lets them not to be executed so often(almost 1 executing per seconds), and +automation radius will be 1 tile. - -This utility affects to ***AutoWaterNearbyCrops, AutoPetNearbyAnimals, AutoHarvest, AutoCollectCollectibles, AutoShakeFruitedPlants, +This utility affects to ***AutoWaterNearbyCrops, AutoPetNearbyAnimals, AutoHarvest, AutoCollectCollectibles, AutoShakeFruitedPlants, AutoDigArtifactSpot, AutoDepositIngredient, and AutoPullMachineResult.*** - **[CONFIG]** - - BalancedMode("Automation" bool, default:true) - whether this utility is enabled. +- RunEveryNthTick("General" uint, default:15) - Run JoE timing loops every Nth tick (1 tick == 1/60 second). ## Mine Info GUI -With this utility, you can check how many stones left, and monster kills tally counter, and whether ladder has spawned in mines. -You can see those when your mouse hovered over the icons. +With this utility, you can check how many stones left, and monster kills tally counter, and whether ladder has spawned in mines. +You can see those when your mouse hovered over the icons. **[CONFIG]** - -- MineInfoGUI("UIs", bool, default:true) - whether this utility is enabled. +- MineInfoGUI("UIs", bool, default:true) - whether this utility is enabled. ## Auto Water Nearby Crops -With this utility, the crops planted on the soil will be watered automatically. -To use this, you must have at least one of Watering Can and it to have enough water within, and this costs stamina of the farmer each crops. +With this utility, the crops planted on the soil will be watered automatically. +To use this, you must have at least one of Watering Can and it to have enough water within, and this costs stamina of the farmer each crops. **[CONFIG]** - -- AutoWaterNearbyCrops("Automation", bool, default:true) - whether this utility is enabled.  - - +- AutoWaterNearbyCrops("Automation", bool, default:true) - whether this utility is enabled. - AutoWaterRadius("Automation", int, default:1) - How far tiles can be affected by this utility. - - - FindCanFromInventory("Automation", bool, default:true) - Find Can from entire inventory or just held by player. + ## Auto Refill Watering Can You can refill your watering can automatically from nearby water source. **[CONFIG]** - -- AutoRefillWateringCan("Automation", bool, default:true) - whether this utility is enabled.  +- AutoRefillWateringCan("Automation", bool, default:true) - whether this utility is enabled. ## Gift Information Tooltip ![](https://i.imgur.com/NOYidaU.gif) - -With this utility, you can check how much do villagers like, dislike the gift before giving it to them. +With this utility, you can check how much do villagers like, dislike the gift before giving it to them. - **[CONFIG]** - - GiftInformation("UIs", bool, default:true) - whether this utility is enabled. ## Auto Pet Nearby Animals -With this utility, you don't have to click on animals to pet, just get close to them. +With this utility, you don't have to click on animals to pet, just get close to them. **[CONFIG]** - - AutoPetNearbyAnimals("Automation", bool, default:false) - whether this utility is enabled. - - - AutoPetRadius("Automation", int, default:1) - How far tiles can be affected by this utility. ## Auto Animal Door -With this utility, animal doors will open in morning if it is sunny and not winter, and close at the time day changed without click it manually. +With this utility, animal doors will open in morning if it is sunny and not winter, and close at the time day changed without click it manually. **[CONFIG]** - - - - AutoAnimalDoor("Automation", bool, default:true) - whether this utility is enabled. ## AFK Fishing Are you tired to deal with fishing? When this utility is enabled, your computer will catch fish instead of you. -This was requested by @GastlyMister. Many thanks! +This was requested by @GastlyMister. Many thanks! **[CONFIG]** - - AutoFishing("Automation", bool, default:false) - whether this plays fishing minigame. - - -- CPUThresholdFishing("Automation", float, default:0.2 min:0.0 max:0.5) - determines how often cpu reel up the rod. - - -- ThrowPower("Automation", float, default:1.0 min:0.0 max:1.0) - How strong a bobber will be thrown. - - +- CPUThresholdFishing("Automation", float, default:0.2 min:0.0 max:0.5) - determines how often cpu reel up the rod. +- ThrowPower("Automation", float, default:1.0 min:0.0 max:1.0) - How strong a bobber will be thrown. - ThresholdStaminaPercentage("Automation", int, default:20 min:10 max:60) - If farmer's stamina percentage is lower than this value, AFK mode will be stopped. - - -- AutoReelRod("Automation", bool, default:true) - whether it automatically reels up the rod when fish nibbled. - - +- AutoReelRod("Automation", bool, default:true) - whether it automatically reels up the rod when fish nibbled. - ToggleAFKFishing("Controls", SButton, default: 'End') - The button to activate/deactivate AFK fishing mode. @@ -141,136 +106,157 @@ Are you tired to deal with fishing? When this utility is enabled, your computer This feature shows the information about the fish when playing fishing minigame. - **[CONFIG]** - - FishingInfo("UIs", bool, default:true) - whether this utility enabled. -## Auto Gate +## Auto Gate ![Auto Gate](https://i.imgur.com/ZUiI9Zr.gif) - -Are you tired of clicking fence gates? Then try this. -This feature let gates open when farmer is close to them, and otherwise, close them automatically. -It should work with both single-player and coop game modes. -This was requested by @plaah007. Thanks alot! +Are you tired of clicking fence gates? Then try this. +This feature let gates open when farmer is close to them, and otherwise, close them automatically. +It should work with both single-player and coop game modes. +This was requested by @plaah007. Thanks alot! **[CONFIG]** - - AutoGate("Automation", bool, default:true) - whether this utility enabled. ## Auto Eat -This utility let the farmer to eat something automatically when his/her health or stamina is low. -These threshold ratio can be changed. -This was requested by @GastlyMister. thanks! +This utility let the farmer to eat something automatically when his/her health or stamina is low. +These threshold ratio can be changed. +This was requested by @GastlyMister. thanks! **[CONFIG]** - - - - AutoEat("Automation", bool, default:false) - whether this utility enabled. - - - StaminaToEatRatio("Automation", float, default:0.3 min:0.3 max:0.8) - the threshold ratio of stamina to eat something - - - HealthToEatRatio("Automation", float, default:0.3 min:0.3 max:0.8) - the threshold ratio of health to eat something ## Auto Harvest -This utility let the farmer to harvest crops (and spring onions) automatically when he/she gets closed to it. +This utility let the farmer to harvest crops (and spring onions) automatically when he/she gets closed to it. **[CONFIG]** - -AutoHarvest("Automation", bool, default:false) - whether this utility enabled. -ProtectNectarProducingFlower("Automation", bool, default:true) - this option protects flowers producing nectar not to be Auto harvested. -AutoHarvestRadius("Automation", int, default:1) - How far tiles can be affected by this utility. -HarvestException("Automation", List) - Crop id list not to be auto harvested. -KeyToggleBlackList("Controls", SButton, default:"F2") - Add/Remove crop under cursor to/from blacklist. +- AutoHarvest("Automation", bool, default:false) - whether this utility enabled. +- ProtectNectarProducingFlower("Automation", bool, default:true) - this option protects flowers producing nectar not to be Auto harvested. +- AutoHarvestRadius("Automation", int, default:1) - How far tiles can be affected by this utility. +- HarvestException("Automation", List) - Crop id list not to be auto harvested. +- KeyToggleBlackList("Controls", SButton, default:"F2") - Add/Remove crop under cursor to/from blacklist. ## Auto Destroy Dead Crops This utility destorys dead crops automatically when he/she gets closed to it. **[CONFIG]** - -AutoDestroyDeadCrops("Automation", bool, default:true) - whether this utility enabled. +- AutoDestroyDeadCrops("Automation", bool, default:true) - whether this utility enabled. ## Auto Collect Collectibles -This utility let the farmer to collect collectibles (crystals, forages, animal products, and so on) automatically -when he/she gets closed to it. +This utility let the farmer to collect collectibles (crystals, forages, animal products, and so on) automatically when he/she gets closed to it. **[CONFIG]** - -AutoCollectCollectibles("Automation", bool, default:false) - whether this utility enabled. -AutoCollectRadius("Automation", int, default:1) - How far tiles can be affected by this utility. +- AutoCollectCollectibles("Automation", bool, default:false) - whether this utility enabled. +- AutoCollectRadius("Automation", int, default:1) - How far tiles can be affected by this utility. ## Auto Shake Fruited Plants -This utility shakes fruited tree(pines, acorns, apples, cherries, and so on) and berry bushes -automatically when the farmer gets closed to it. +This utility shakes fruited tree(pines, acorns, apples, cherries, and so on) and berry bushes automatically when the farmer gets closed to it. **[CONFIG]** - -AutoShakeFruitedPlamts("Automation", bool, default:true) - whether this utility enabled. -AutoShakeRadius("Automation", int, default:1) - How far tiles can be affected by this utility. +- AutoShakeFruitedPlamts("Automation", bool, default:true) - whether this utility enabled. +- AutoShakeRadius("Automation", int, default:1) - How far tiles can be affected by this utility. ## Auto Dig Artifact Spot -This utility digs artifact spots nearby the farmer automatically. +This utility digs artifact spots nearby the farmer automatically. -**[CONFIG]** +Currently does **NOT** handle Seed Spots. -AutoDigArtifactSpot("Automation", bool, default:false) - whether this utility enabled. -AutoDigRadius("Automation", int, default:1) - How far tiles can be affected by this utility. -FindHoeFromInventory("Automation", bool, default:true) - Find hoe from entire inventory or just held by player. +**[CONFIG]** +- AutoDigArtifactSpot("Automation", bool, default:false) - whether this utility enabled. +- AutoDigRadius("Automation", int, default:1) - How far tiles can be affected by this utility. +- FindHoeFromInventory("Automation", bool, default:true) - Find hoe from entire inventory or just held by player. ## Auto Deposit Ingredient -This utility will try to deposit ingredient you held to nearby machines automatically. +This utility will try to deposit ingredient you held to nearby machines automatically. **[CONFIG]** +- AutoDepositIngredient("Automation", bool, default:false) - whether this utility enabled. +- MachineRadius("Automation", int, default:1) - How far tiles can be affected by this utility. +- AutoDepositSeedMaker("Automation, bool, default:false) - Whether to auto-deposit into Seed Makers. -AutoDepositIngredient("Automation", bool, default:false) - whether this utility enabled. -MachineRadius("Automation", int, default:1) - How far tiles can be affected by this utility. ## Auto Pull Machine Result -This utility will try to pull results from nearby machines and give it to the farmer automatically. +This utility will try to pull results from nearby machines and give it to the farmer automatically. **[CONFIG]** +- AutoPullMachineResult("Automation", bool, default:true) - whether this utility enabled. +- MachineRadius("Automation", int, default:1) - How far tiles can be affected by this utility. + + +## List of Valid Machines (for auto-push and auto-pull) +- MachineTypes [List of Machine Name strings] - You can disable or add new machine types by editing config.json. If a new version of SdV comes out with a new machine, you can add it here without waiting for a new version of JoE! + - "Bait Maker", + "Bee House", + "Bone Mill", + "Cask", + "Charcoal Kiln", + "Cheese Press", + "Coffee Maker", + "Crab Pot", + "Crystalarium", + "Dehydrator", + "Deluxe Worm Bin", + "Fish Smoker", + "Furnace", + "Heavy Furnace", + "Heavy Tapper", + "Incubator", + "Keg", + "Loom", + "Lightning Rod", + "Mayonnaise Machine", + "Mushroom Box", + "Mushroom Log", + "Oil Maker", + "Preserves Jar", + "Recycling Machine", + "Seed Maker", + "Sewing Machine", + "Slime Egg-Press", + "Slime Incubator", + "Statue Of Endless Fortune", + "Statue Of Perfection", + "Tapper", + "Wood Chipper", + "Worm Bin", -AutoPullMachineResult("Automation", bool, default:true) - whether this utility enabled. -MachineRadius("Automation", int, default:1) - How far tiles can be affected by this utility. - ## Auto Pet Nearby Pets -Oh, seriously you want to pet pets automatically? -All right, this utility pets nearby pets automatically. +Oh, seriously you want to pet pets automatically? +All right, this utility pets nearby pets automatically. **[CONFIG]** - - AutoPetNearbyPets("Automation", bool, default:false) - whether this utility is enabled. - AutoPetRadius("Automation", int, default:1 min:1 max:3) - How far tiles can be affected by this utility. ## Fishing Probabilities Info -This utility let you know what fish could be caught (and estimated probability of catching) when you are fishing. +This utility let you know what fish could be caught (and estimated probability of catching) when you are fishing. **[CONFIG]** - - FishingProbabilitiesInfo("UIs", bool, default:false) - whether this utility is enabled. - - +- ProbBoxMaxFish("UIs", int, default:10 min:5 max:25) - How many fish to show per column. - ProbBoxCoordinates("UIs", Point, default:[100,400]) - Top-left coordinates of the window. - - - MorePreciseProbabilities("UIs", bool, default:true) - Displays more plactical and precise probabiilities. +- TrialOfExamine("UIs", int, default:10 min:1 max:50) - Trial number of computing probabilities. +## Fishing Tackle Info +This utility lets you know what type of bait and bobber you have equipped, and how many uses you have left. -- TrialOfExamine("UIs", int, default:10 min:1 max:50) - Trial number of computing probabilities. +**[CONFIG]** +- FishingTackleInfo("UIs", bool, default:false) - whether this utility is enabled. +- TackleBoxAttach("UIs", bool, default:false) - Attaches the tackle info window to fishing probabilites. +- TackleBoxCoordinates("UIs", Point, default:[40,500]) - Top-left coordinates of the window. ## Show Shipping Price This utility shows estimated total shipping price when you opened shipping box. **[CONFIG]** - - EstimateShippingPrice("UIs", bool, default:true) - whether this utility is enabled. - - PriceBoxCoordinates("UIs", Point, default:[100,100]) - Top-left coordinates of the window. ## Unify Flower Colors @@ -278,126 +264,93 @@ This utility unifies flower colors to reduce occupied spaces according to its sp In config file, you can change the color using "R, G, B, A" format. **[CONFIG]** - - UnifyFlowerColors("Misc", bool, default:false) - whether this utility is enabled. - - - JazzColor("Misc", Color, default:{0, 255, 255, 255}) - The color of Blue Jazz. - - - TulipColor("Misc", Color, default:{255, 0, 0, 255}) - The color of Turip. - - - PoppyColor("Misc", Color, default:{255, 69, 0, 255}) - The color of Poppy. - - - SummerSpangleColor("Misc", Color, default:{255, 215, 0, 255}) - The color of Summer Spangle. - - - FairyRoseColor("Misc", Color, default:{216, 191, 216, 255}) - The color of Fairy Rose. - - - ButtonToggleFlowerColorUnification("Controls", SButton, default: 'L') - The button to register/unregister flowers to unify their colors. - - - CustomizedFlowerColors("Misc", Dictionary) - Customized flower colors for unification. ## Auto Loot Treasures - - This utility loots all acceptable items in treasure box, not chests player placed or shipping bin. (e.g. fishing treasures, mine treasures) - **[CONFIG]** - - - AutoLootTreasures("Automation", bool, default:true) - whether this utility is enabled. - - - CloseTreasureWhenAllLooted("Automation", bool, default:false) - Closes the treasure chest menu when all items taken. ## Collect Letter Attachments And Quests - - This feature collects attached items or accepts quests when you opened mail contains those. **[CONFIG]** - - - CollectLetterAttachmentsAndQuests("Automation", bool, default:false) - whether this utility is enabled. ## Pause When Idle - - This feature pauses game when you are not in work. - It helps you not to waste in-game time when idling. **[CONFIG]** - - - PauseWhenIdle("Misc", bool, default:false) - whether this utility is enabled. - - - IdleTimeout("Misc", int, default:180 min:1 max:300) - Timeout needed to pause the game in seconds. - - - PauseNotificationX("Not on menu", int, default:100) - X position of paused notification. - - - PauseNotificationY("Not on menu", int, default:700) - Y position of paused notification. ## Auto Pick Up Trash - - This feature searches trash can and pick up trash without being detected. - +**[CONFIG]** - AutoPickUpTrash("Automation", bool, default:false) - whether this utility is enabled. - - - ScavengingRadius("Automation", int, default:2 min:1 max:3) - How far tiles can be affected by this utility. ## Auto Shearing and Milking - - This feature let you shear/milk nearby mature sheep/cows automatically when you held shears/bucket. - +**[CONFIG]** - AutoShearingAndMilking("Automation", bool, default:true) - whether this utility is enabled. - - - AnimalHarvestRadius("Automation", int, default:1 min:1 max:3) - How far tiles can be affected by this utility. ## Farm Cleaner - - This feature will clean up small rocks, twigs, and weeds in farm. - Please note that it can consume the farmer's stamina relatively easily. - You have to select appropriate tool in hotbar to use. - **[CONFIG]** - - RadiusFarmCleanup("Automation", int, default:1 min:1 max:3) - How far tiles can be affected by this utility. - - - CutWeeds("Automation", bool, default:false) - Cuts weeds nearby (requires Scythe). - - - BreakRocks("Automation", bool, default:false) - Breaks small rocks nearby (requires Pickaxe). +- ChopTwigs("Automation", bool, default:false) - Chops twigs nearby (requires Axe). + +## Don't Eat That +[Don't Eat That](https://www.nexusmods.com/stardewvalley/mods/1951) was an old mod by [Pyrohead37]. Since it hasn't been updated since 2019, I've decompiled the code, updated it, and added it to JoE! -- ChopTwigs("Automation", bool, default:false) - Chops twigs nearby (requires Axe). \ No newline at end of file +**[CONFIG]** +- DontEatCategories [List of Category strings] - Which categories of items NOT to eat. Defaults are: + - Artisan Goods + - Animal Product + - Crop + - Fish + - Flower + - Harmful + - Vegetable +- DontEat [List of Item name strings] - Which specific ITEMS not to eat. It's okay if they overlap categories. Defaults: + - Holly + - Oil + - Red Mushroom + - Sap + - Truffle +- DoEat [List of Item name strings] - Which specific ITEMS to **ALLOW** eating. These are actually _removed_ from the "don't eat" list that was compiled from the above entries. Defaults: + - Mayonnaise + - Beer + - Green Tea diff --git a/GloryOfEfficiency/GloryOfEfficiency.csproj b/GloryOfEfficiency/GloryOfEfficiency.csproj new file mode 100644 index 0000000..fb2f67b --- /dev/null +++ b/GloryOfEfficiency/GloryOfEfficiency.csproj @@ -0,0 +1,64 @@ + + + + + net6.0 + Library + Properties + GloryOfEfficiency + GloryOfEfficiency + 512 + 1.0.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 3 + + + true + pdbonly + true + bin\Release\ + TRACE + prompt + 3 + + + Always + + + + + + + + + + + + + + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + diff --git a/GloryOfEfficiency/Harmony/HarmonyPatcher.cs b/GloryOfEfficiency/Harmony/HarmonyPatcher.cs new file mode 100644 index 0000000..78fcade --- /dev/null +++ b/GloryOfEfficiency/Harmony/HarmonyPatcher.cs @@ -0,0 +1,15 @@ +using HarmonyLib; + +namespace GloryOfEfficiency.Harmony +{ + internal class HarmonyPatcher + { + private static HarmonyLib.Harmony harmony = new HarmonyLib.Harmony("com.pome.joe"); + + public static void DoPatching() + { + harmony.PatchAll(); + } + + } +} diff --git a/JoysOfEfficiency/Huds/FishInformationHud.cs b/GloryOfEfficiency/Huds/FishInformationHud.cs similarity index 89% rename from JoysOfEfficiency/Huds/FishInformationHud.cs rename to GloryOfEfficiency/Huds/FishInformationHud.cs index 63a224d..c06b016 100644 --- a/JoysOfEfficiency/Huds/FishInformationHud.cs +++ b/GloryOfEfficiency/Huds/FishInformationHud.cs @@ -1,6 +1,6 @@ using System; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; @@ -8,29 +8,26 @@ using StardewValley.Menus; using Object = StardewValley.Object; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { internal class FishInformationHud { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; private static ITranslationHelper Translation => InstanceHolder.Translation; public static void DrawFishingInfoBox(SpriteBatch batch, BobberBar bar, SpriteFont font) { int width = 0, height = 120; - float scale = 1.0f; + String whichFish = bar.whichFish; + int fishSize = bar.fishSize; + int fishQuality = bar.fishQuality; + bool treasure = bar.treasure; + bool treasureCaught = bar.treasureCaught; + float treasureAppearTimer = bar.treasureAppearTimer; - int whichFish = Reflection.GetField(bar, "whichFish").GetValue(); - int fishSize = Reflection.GetField(bar, "fishSize").GetValue(); - int fishQuality = Reflection.GetField(bar, "fishQuality").GetValue(); - bool treasure = Reflection.GetField(bar, "treasure").GetValue(); - bool treasureCaught = Reflection.GetField(bar, "treasureCaught").GetValue(); - float treasureAppearTimer = Reflection.GetField(bar, "treasureAppearTimer").GetValue() / 1000; - - bool perfect = Reflection.GetField(bar, "perfect").GetValue(); + bool perfect = bar.perfect; if (perfect) { if(fishQuality >= 2) diff --git a/GloryOfEfficiency/Huds/FishingProbabilitiesBox.cs b/GloryOfEfficiency/Huds/FishingProbabilitiesBox.cs new file mode 100644 index 0000000..863d977 --- /dev/null +++ b/GloryOfEfficiency/Huds/FishingProbabilitiesBox.cs @@ -0,0 +1,667 @@ +using GloryOfEfficiency.Core; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Netcode; +using StardewValley; +using StardewValley.GameData; +using StardewValley.GameData.Locations; +using StardewValley.Locations; +using StardewValley.Menus; +using StardewValley.Tools; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using xTile.Dimensions; +using Game1 = StardewValley.Game1; +using Object = StardewValley.Object; +using Rectangle = Microsoft.Xna.Framework.Rectangle; + +namespace GloryOfEfficiency.Huds +{ + public class FishingProbabilitiesBox + { + private static Dictionary _fishingDictionary; + private static Dictionary _attachmentDictionary; + + private static bool _isFirstTimeOfFishing = true; + + public static void UpdateProbabilities(FishingRod rod) + { + if (rod.isFishing) + { + if (_isFirstTimeOfFishing && InstanceHolder.Config.FishingProbabilitiesInfo) + { + // Only run the probablies once when line is cast + _isFirstTimeOfFishing = false; + + // Game Location + GameLocation location = Game1.currentLocation; + + // Water Depth + Rectangle rectangle = new(location.fishSplashPoint.X * 64, location.fishSplashPoint.Y * 64, 64, 64); + Rectangle value = new((int)rod.bobber.X - 80, (int)rod.bobber.Y - 80, 64, 64); + bool flag = rectangle.Intersects(value); + int clearWaterDistance = rod.clearWaterDistance; + + // Bobber Location + Vector2 vector = new(rod.bobber.X / 64f, rod.bobber.Y / 64f); + + // Populate Fish and Tackle + _fishingDictionary = GetFishes(location, vector, clearWaterDistance + (flag ? 1 : 0), Game1.player, rod, InstanceHolder.Config.MorePreciseProbabilities ? InstanceHolder.Config.TrialOfExamine : 1); + } + + if (InstanceHolder.Config.FishingTackleInfo) + _attachmentDictionary = GetAttachments(rod); + } + + // Clear out lists when not fishing + else + { + _isFirstTimeOfFishing = true; + _fishingDictionary = null; + _attachmentDictionary = null; + } + } + + public static void PrintFishingInfo() + { + // Draw Fishing Window + int x_pos_add = 0; + if (InstanceHolder.Config.FishingProbabilitiesInfo && _fishingDictionary != null) + x_pos_add = DrawProbBox(_fishingDictionary); + + // Draw Tackle Window + if (InstanceHolder.Config.FishingTackleInfo && _attachmentDictionary != null && _attachmentDictionary.Count > 0) + DrawTackleBox(_attachmentDictionary, x_pos_add); + } + + private static Dictionary GetAttachments(FishingRod rod) + { + Dictionary dictList = new(); + + // Get Bait and Tackle from Rod + Object baitObject = rod.GetBait(); + List tackleObjects = rod.GetTackle(); + + // Add Bait + if (baitObject != null) + dictList[baitObject.QualifiedItemId] = baitObject.Stack; + + // Add Tackle + foreach (Object tackle in tackleObjects) + if (tackle != null) + dictList[tackle.QualifiedItemId] = FishingRod.maxTackleUses - tackle.uses.Value; + + return dictList; + } + + private static Dictionary GetFishes(GameLocation location, Vector2 bobbleTile, int waterDepth, Farmer player, FishingRod rod, int trial = 1) + { + // Run X amount of trials and get the results + List> dictList = new(); + for (int i = 0; i < trial; i++) + { + // Mineshaft have to be handled slightly differently + if (location is MineShaft) + dictList.Add(GetFishesMine((MineShaft)location, bobbleTile, waterDepth, player, rod)); + else + dictList.Add(GetFishesGeneric(bobbleTile, waterDepth, player, rod)); + } + + // Shuffle and get a list of valid items + Dictionary shuffledDict = ShuffleAndAverageFishingDictionary(dictList); + Dictionary fishDict = shuffledDict.OrderByDescending(x => x.Value).Where(kv => !IsGarbage(kv.Key)).ToDictionary(x => x.Key, x => x.Value); + + // Add in sum of Garbage items if they have a probability + Dictionary garbageDict = shuffledDict.OrderByDescending(x => x.Value).Where(kv => IsGarbage(kv.Key)).ToDictionary(x => x.Key, x => x.Value); + double garbageSum = garbageDict.Sum(kv => kv.Value); + if (garbageSum > 0.0001) + fishDict.Add("(O)168", garbageSum); + + // Get probability to 100% + double totalSum = fishDict.Sum(kv => kv.Value); + Dictionary finalDict = fishDict.ToDictionary(x => x.Key, x => x.Value / totalSum); + + return finalDict; + } + + private static Dictionary GetFishesMine(MineShaft shaft, Vector2 bobbleTile, int waterDepth, Farmer player, FishingRod rod) + { + Dictionary dict = new(); + double p; + + // If player is using training rod in mines, return trash + if (rod.QualifiedItemId.Contains("TrainingRod")) + { + dict["(O)168"] = 1; + return dict; + } + + // Setup initial chance + double num = 1.0; + num += 0.4 * player.FishingLevel; + num += waterDepth * 0.1; + + // Lure Check + if (rod.HasCuriosityLure()) + num += 5.0; + + // Target Bait Check + string textTarget = rod.GetBait()?.Name ?? ""; + + // Add specific fish based on mine level + int level = shaft.getMineArea(); + switch (level) + { + case 0: + case 10: + num += textTarget.Contains("Stonefish") ? 10 : 0; + p = 0.02 + 0.01 * num; + dict.Add("(O)158", p); + break; + case 40: + num += textTarget.Contains("Ice Pip") ? 10 : 0; + p = 0.015 + 0.009 * num; + dict.Add("(O)161", p); + break; + case 80: + num += textTarget.Contains("Lava Eel") ? 10 : 0; + p = 0.01 + 0.008 * num; + dict.Add("(O)162", p); + break; + default: + return dict; + } + + // Get general fish data on level 10/40, and add Cave Jelly and trash to level 80 + if (level == 10 || level == 40) + return ConcatDictionary(dict, GetFishesGeneric(bobbleTile, waterDepth, player, rod, "UndergroundMine")); + else if (level == 80) + { + p = 0.05 + player.LuckLevel * 0.05; + dict.Add("(O)CaveJelly", p); + dict.Add("(O)168", 1); + } + + return dict; + } + + private static Dictionary GetFishesGeneric(Vector2 bobberTile, int waterDepth, Farmer player, FishingRod rod, string locationName = null) + { + Dictionary dictFish = new(); + + // GameData + GameLocation location = Game1.currentLocation; + Dictionary dictionary = DataLoader.Locations(Game1.content); + LocationData locationData = ((location != null) ? location.GetData() : GameLocation.GetData(locationName)); + Dictionary allFishData = DataLoader.Fish(Game1.content); + Season seasonForLocation = Game1.GetSeasonForLocation(location); + + // Get Fish Area for Tile + if (location == null || !location.TryGetFishAreaForTile(bobberTile, out var id, out var _)) + id = null; + + // Magic Bait + bool flagMagicBait = false; // flag + bool hasCuriosityLure = false; + string textTarget = null; + flagMagicBait = rod.HasMagicBait(); + + // Curiosity Lure + hasCuriosityLure = rod.HasCuriosityLure(); + + // Targeted Bait + StardewValley.Object bait = rod.GetBait(); + if (bait?.QualifiedItemId == "(O)SpecificBait" && bait.preservedParentSheetIndex.Value != null) + textTarget = "(O)" + bait.preservedParentSheetIndex.Value; + + // Keys + HashSet ignoreQueryKeys = (flagMagicBait ? GameStateQuery.MagicBaitIgnoreQueryKeys : null); + Point tilePoint = player.TilePoint; + + // Fish Data + IEnumerable enumerable = dictionary["Default"].Fish; + if (locationData != null && locationData.Fish?.Count > 0) + enumerable = enumerable.Concat(locationData.Fish); + + // Add Inherited Locations if found in spawn data + IEnumerable inherited = enumerable.Where(x => x.Id.Contains("LOCATION_FISH")); + foreach (SpawnFishData spawn in inherited) + { + string[] inheritedLocation = spawn.Id.Split(' '); + enumerable = enumerable.Concat(dictionary[inheritedLocation[1]].Fish.Where(x => x.CanBeInherited)); + } + + // Gather all fish and order them by presidence + enumerable = from p in enumerable + orderby p.Precedence, Game1.random.Next() + select p; + + // Loop through spawn data + foreach (SpawnFishData spawn in enumerable) + { + string fishIDQualified = spawn.ItemId ?? spawn.Id; + string fishID = Regex.Replace(fishIDQualified, "\\(O\\)", ""); + + // If we get multiple options, select the first + if (fishIDQualified.Contains('|')) + { + fishIDQualified = fishIDQualified.Split('|')[0]; + fishID = Regex.Replace(fishIDQualified, "\\(O\\)", ""); + } + + // Secret Notes / Inherited Fish Types + if (fishIDQualified.Contains("SECRET_NOTE_OR_ITEM") || fishIDQualified.Contains("LOCATION_FISH")) continue; + + // Not the correct area or season + if ((spawn.FishAreaId != null && id != spawn.FishAreaId) || (spawn.Season.HasValue && !flagMagicBait) && spawn.Season != seasonForLocation) + continue; + + // Player Position + Rectangle? playerPosition = spawn.PlayerPosition; + if (playerPosition.HasValue && !playerPosition.GetValueOrDefault().Contains(tilePoint.X, tilePoint.Y)) + continue; + + // Bobber Position + playerPosition = spawn.BobberPosition; + if ((playerPosition.HasValue && !playerPosition.GetValueOrDefault().Contains((int)bobberTile.X, (int)bobberTile.Y)) || player.FishingLevel < spawn.MinFishingLevel || waterDepth < spawn.MinDistanceFromShore || (spawn.MaxDistanceFromShore > -1 && waterDepth > spawn.MaxDistanceFromShore) || (spawn.RequireMagicBait && !flagMagicBait)) + continue; + + // Spawn Conditions + if (spawn.Condition != null && !GameStateQuery.CheckConditions(spawn.Condition, location, null, null, null, null, ignoreQueryKeys)) + continue; + + // We have caught the limit of the fish + if (spawn.CatchLimit > 0 && player.fishCaught.TryGetValue(fishIDQualified, out var value2) && value2[0] >= spawn.CatchLimit) + continue; + + // If fish it not actually a fish + if (!allFishData.TryGetValue(fishID, out var fishArray)) + { + float chance = spawn.GetChance(hasCuriosityLure, player.DailyLuck, player.LuckLevel, (float value, IList modifiers, QuantityModifier.QuantityModifierMode mode) => Utility.ApplyQuantityModifiers(value, modifiers, mode, location), spawn.ItemId == textTarget); + chance = Math.Min(chance, 1f); + dictFish[fishIDQualified] = chance; + + // If this item has a 100% chance, we stop + if (chance >= 1f) + break; + else + continue; + } + + // Split Fish Data to Array + string[] fishData = fishArray.Split('/'); + + // Training Rod Check + bool flagTrainingRod = rod.QualifiedItemId == "(T)TrainingRod"; + if (flagTrainingRod) + { + bool? canUseTrainingRod = spawn.CanUseTrainingRod; + if (canUseTrainingRod.HasValue) + { + if (!canUseTrainingRod.GetValueOrDefault()) + continue; + else if (ArgUtility.TryGetInt(fishData, 1, out var value, out var error) && value >= 50) + continue; + } + } + + // If we do not ingore requirements, check and get spawn chance + if (!spawn.IgnoreFishDataRequirements) + { + // Time and Weather Check if not using Magic Bait + if (!flagMagicBait) + { + // Time of Day Check + if (!ArgUtility.TryGet(fishData, 5, out var timeData, out var errorTime)) + continue; + + string[] timeArray = ArgUtility.SplitBySpace(timeData); + bool flagTime = false; + for (int i = 0; i < timeArray.Length; i += 2) + { + if (!ArgUtility.TryGetInt(timeArray, i, out var startTime, out errorTime) || !ArgUtility.TryGetInt(timeArray, i + 1, out var stopTime, out errorTime)) + continue; + + if (Game1.timeOfDay >= startTime && Game1.timeOfDay < stopTime) + { + flagTime = true; + break; + } + } + + if (!flagTime) + continue; + + // Weather Check + if (!ArgUtility.TryGet(fishData, 7, out var value, out var errorWeather)) + continue; + + if (!value.Equals("both")) + { + if (value.Equals("sunny") && location.IsRainingHere()) + continue; + if (value.Equals("rainy") && !location.IsRainingHere()) + continue; + } + } + + // Fishing Level Check + if (ArgUtility.TryGetInt(fishData, 12, out var value8, out var error) && player.FishingLevel < value8) + continue; + + // Max Depth, Spawn Chance, Spawn Depth Check + if (!ArgUtility.TryGetInt(fishData, 9, out var maxDepth, out error) || !ArgUtility.TryGetFloat(fishData, 10, out var spawnMultiplier, out error) || !ArgUtility.TryGetFloat(fishData, 11, out var depthMultiplier, out error)) + continue; + + // Chance to Catch + float num = depthMultiplier * spawnMultiplier; + spawnMultiplier -= (float)Math.Max(0, maxDepth - waterDepth) * num; + spawnMultiplier += (float)player.FishingLevel / 50f; + if (flagTrainingRod) + spawnMultiplier *= 1.1f; + + spawnMultiplier = Math.Min(spawnMultiplier, 0.9f); + if ((double)spawnMultiplier < 0.25 && hasCuriosityLure) + if (spawn.CuriosityLureBuff > -1f) + spawnMultiplier += spawn.CuriosityLureBuff; + else + { + float num2 = 0.25f; + float num3 = 0.08f; + spawnMultiplier = (num2 - num3) / num2 * spawnMultiplier + (num2 - num3) / 2f; + } + + if (spawn.ItemId == textTarget) + spawnMultiplier *= 1.66f; + + if (spawn.ApplyDailyLuck) + spawnMultiplier += (float)player.DailyLuck; + + List chanceModifiers = spawn.ChanceModifiers; + if (chanceModifiers != null && chanceModifiers.Count > 0) + spawnMultiplier = Utility.ApplyQuantityModifiers(spawnMultiplier, spawn.ChanceModifiers, spawn.ChanceModifierMode, location); + + // Only if fish has a chance to sapwn + if (spawnMultiplier > 0) + { + spawnMultiplier = Math.Min(spawnMultiplier, 1f); + dictFish[fishIDQualified] = spawnMultiplier; + } + + // If this item has a 100% chance, we stop + if (spawnMultiplier >= 1f) + break; + } + + // If we ignore requirements, get chance from spawn + else + { + float chance = spawn.GetChance(hasCuriosityLure, player.DailyLuck, player.LuckLevel, (float value, IList modifiers, QuantityModifier.QuantityModifierMode mode) => Utility.ApplyQuantityModifiers(value, modifiers, mode, location), spawn.ItemId == textTarget); + chance = Math.Min(chance, 1f); + dictFish[fishIDQualified] = chance; + + // If this item has a 100% chance, we stop + if (chance >= 1f) + break; + } + } + + return dictFish; + } + + private static bool IsGarbage(string item) + { + // Return false for any Non-Objects + if (!item.Contains("(O)")) + return false; + + // Get object information + string itemID = Regex.Replace(item, "\\(O\\)", ""); + var objectData = Game1.objectData[itemID]; + + // Fish items that are not fish + if (objectData != null && objectData.ContextTags != null && objectData.ContextTags.Contains("fish_nonfish") && !objectData.ContextTags.Contains("counts_as_fish_catch")) + return true; + + // JoJa Garbage + if (item == "(O)167" || item == "(O)168" || item == "(O)169" || item == "(O)170" || item == "(O)171" || item == "(O)172") + return true; + + return false; + } + + private static Dictionary GetFinalProbabilities(Dictionary dict) + { + Dictionary result = new(); + double ratio = 1.0; + + // Get the result of each fish while moving down from 100% + foreach (KeyValuePair kv in dict) + { + result.Add(kv.Key, kv.Value * ratio); + ratio *= (1 - kv.Value); + } + + return result; + } + + private static Dictionary ShuffleAndAverageFishingDictionary(IEnumerable> list) + { + List> dicts = list.Select(dict => GetFinalProbabilities(ShuffleDictionary(dict))).ToList(); + return AverageDictionary(dicts); + } + + private static Dictionary ShuffleDictionary(Dictionary dict) + { + // Get the last value of the dictionary if higher than 100% + double? probability = null; + string LastKey = ""; + if (dict[dict.Keys.Last()] >= 1f) + { + LastKey = dict.Keys.Last(); + dict.Remove(LastKey); + + // Get the probabilities of the remaining fish + foreach (KeyValuePair kv in dict) + if (!probability.HasValue) + probability = 1 - kv.Value; + else + probability *= 1 - kv.Value; + } + + // Shuffle the remaining items + KeyValuePair[] pairs = dict.ToArray(); + Utility.Shuffle(Game1.random, pairs); + Dictionary itemsShuffled = pairs.ToDictionary(x => x.Key, x => x.Value); + + // Insert the probability of the 100% + if (LastKey != "") + itemsShuffled[LastKey] = probability ?? 1; + + + return itemsShuffled; + } + + private static Dictionary AverageDictionary(List> list) + { + Dictionary sum = new(); + foreach (Dictionary elem in list) + { + foreach (KeyValuePair pair in elem) + { + if (sum.ContainsKey(pair.Key)) + sum[pair.Key] += pair.Value; + else + sum.Add(pair.Key, pair.Value); + } + } + + return MagnifyProbabilities(sum, 1.0 / list.Count); + } + + private static Dictionary MagnifyProbabilities(Dictionary dict, double ratio) + { + return dict.ToDictionary(kv => kv.Key, kv => kv.Value * ratio); + } + + private static Dictionary ConcatDictionary(IDictionary a, Dictionary b) + { + Dictionary dict = new(a); + + foreach (KeyValuePair kv in b.Where(kv => !dict.ContainsKey(kv.Key))) + dict.Add(kv.Key, kv.Value); + + return dict; + } + + private static int DrawProbBox(Dictionary probabilities) + { + Rectangle window = Game1.game1.Window.ClientBounds; + SpriteBatch b = Game1.spriteBatch; + Size size = GetProbBoxSize(probabilities); + + int yOffset = InstanceHolder.Config.ProbBoxCoordinates.Y; + if (size.Height > window.Height - yOffset) + { + yOffset = window.Height - size.Height; + if (yOffset < 0) + yOffset = 0; + } + + // Draw menu without shadow + IClickableMenu.drawTextureBox(b,Game1.menuTexture,new Rectangle(0, 256, 60, 60),InstanceHolder.Config.ProbBoxCoordinates.X,yOffset,size.Width,size.Height,Color.White,1f,false,-1f); + const int square = (int)(Game1.tileSize / 1.5); + int width = 16; + int x_space = 0; + int x = InstanceHolder.Config.ProbBoxCoordinates.X + 8; + int y = yOffset + 16; + int fishCount = 1; + SpriteFont font = Game1.smallFont; + + // Draw Fish + foreach (KeyValuePair kv in probabilities) + { + if (kv.Key.Contains("SECRET_NOTE")) continue; + string text = $"{kv.Value * 100:f1}%"; + Item fish = ItemRegistry.Create(kv.Key, 1); + fish.drawInMenu(b, new Vector2(x + 8 + x_space, y), 0.70f); + Utility.drawTextWithShadow(b, text, font, new Vector2(x + 32 + square + x_space, y + 18), Color.Black); + + Vector2 textSize = font.MeasureString(text); + int w = square + (int)textSize.X + 64 + x_space; + if (w > width) width = w; + + + // Move cursor based on number of fish + if (fishCount % InstanceHolder.Config.ProbBoxMaxFish == 0) + { + x_space = 8 + w; + y = yOffset + 16; + } + else + y += square + 16; + + // Track Count + fishCount++; + } + + return size.Width; + } + + private static Size GetProbBoxSize(Dictionary probabilities) + { + int width = 16, height = 48; + int square = (int)(Game1.tileSize / 1.5); + int fishCount = 1; + int x_space = 0; + bool y_max = false; + SpriteFont font = Game1.smallFont; + foreach (KeyValuePair kv in probabilities) + { + if (kv.Key.Contains("SECRET_NOTE")) continue; + string text = $"{kv.Value * 100:f1}%"; + Vector2 textSize = font.MeasureString(text); + int w = square + (int)textSize.X + 64 + x_space; + if (w > width) width = w; + + // Increase Height if applicable + if (!y_max) + height += square + 16; + + // Start a new column? + if (fishCount % InstanceHolder.Config.ProbBoxMaxFish == 0) + { + x_space = 8 + w; + y_max = true; + } + + // Index + fishCount++; + } + return new Size(width, height); + } + + private static void DrawTackleBox(Dictionary attachments, int x_add) + { + Rectangle window = Game1.game1.Window.ClientBounds; + SpriteBatch b = Game1.spriteBatch; + Size size = GetTackleBoxSize(attachments); + + // Determine location based on Probability box or defined coordinates + int xOffset, yOffset; + if (InstanceHolder.Config.TackleBoxAttach) { + xOffset = InstanceHolder.Config.ProbBoxCoordinates.X + x_add; + yOffset = InstanceHolder.Config.ProbBoxCoordinates.Y; + } + else + { + xOffset = InstanceHolder.Config.TackleBoxCoordinates.X; + yOffset = InstanceHolder.Config.TackleBoxCoordinates.Y; + } + + // Set the initial yOffset + if (size.Height > window.Height - yOffset) + { + yOffset = window.Height - size.Height; + if (yOffset < 0) + yOffset = 0; + } + + //Draw Window for Bait and Bobbers + IClickableMenu.drawTextureBox(b, Game1.menuTexture, new Rectangle(0, 256, 60, 60), xOffset, yOffset, size.Width, size.Height, Color.White, 1f, false, -1f); + const int square = (int)(Game1.tileSize / 1.5); + int x = xOffset + 8; + int y = yOffset + 16; + SpriteFont font = Game1.smallFont; + + // Add Bait and Tackle + foreach (KeyValuePair kv in attachments) + { + string text = $"{kv.Value}"; + Item tackle = ItemRegistry.Create(kv.Key, 1); + tackle.drawInMenu(b, new Vector2(x + 8, y), 0.70f); + Utility.drawTextWithShadow(b, text, font, new Vector2(x + 32 + square, y + 18), Color.Black); + + y += square + 16; + } + } + + private static Size GetTackleBoxSize(Dictionary attachments) + { + int width = 16, height = 48; + int square = (int)(Game1.tileSize / 1.5); + SpriteFont font = Game1.smallFont; + foreach (KeyValuePair kv in attachments) + { + string text = $"{kv.Value}"; + Vector2 textSize = font.MeasureString(text); + int w = square + (int)textSize.X + 64; + if (w > width) width = w; + height += square + 16; + } + return new Size(width, height); + } + } +} diff --git a/JoysOfEfficiency/Huds/FpsCounter.cs b/GloryOfEfficiency/Huds/FpsCounter.cs similarity index 92% rename from JoysOfEfficiency/Huds/FpsCounter.cs rename to GloryOfEfficiency/Huds/FpsCounter.cs index eb9e897..6ead4dc 100644 --- a/JoysOfEfficiency/Huds/FpsCounter.cs +++ b/GloryOfEfficiency/Huds/FpsCounter.cs @@ -1,10 +1,10 @@ using System; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using StardewModdingAPI.Events; using StardewValley; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { internal class FpsCounter { diff --git a/JoysOfEfficiency/Huds/GiftInformationTooltip.cs b/GloryOfEfficiency/Huds/GiftInformationTooltip.cs similarity index 93% rename from JoysOfEfficiency/Huds/GiftInformationTooltip.cs rename to GloryOfEfficiency/Huds/GiftInformationTooltip.cs index 6361e9b..960b19c 100644 --- a/JoysOfEfficiency/Huds/GiftInformationTooltip.cs +++ b/GloryOfEfficiency/Huds/GiftInformationTooltip.cs @@ -1,13 +1,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using StardewModdingAPI; using StardewValley; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { public class GiftInformationTooltip { @@ -29,7 +29,7 @@ public static void UpdateTooltip() return; } - List npcList = player.currentLocation.characters.Where(a => a != null && a.isVillager()).ToList(); + List npcList = player.currentLocation.characters.Where(a => a != null && a.IsVillager).ToList(); foreach (NPC npc in npcList) { Rectangle npcRect = new Rectangle( @@ -62,7 +62,7 @@ public static void UpdateTooltip() key.Append("gavetoday."); _unableToGift = true; } - else if (npc.canReceiveThisItemAsGift(player.CurrentItem)) + else if (npc.tryToReceiveActiveObject(player, probe: true)) { switch (npc.getGiftTasteForThisItem(player.CurrentItem)) { @@ -90,7 +90,7 @@ public static void UpdateTooltip() } switch (npc.Gender) { - case NPC.female: + case Gender.Female: key.Append("female"); break; default: diff --git a/JoysOfEfficiency/Huds/MineHud.cs b/GloryOfEfficiency/Huds/MineHud.cs similarity index 97% rename from JoysOfEfficiency/Huds/MineHud.cs rename to GloryOfEfficiency/Huds/MineHud.cs index 7d3f053..9e29edb 100644 --- a/JoysOfEfficiency/Huds/MineHud.cs +++ b/GloryOfEfficiency/Huds/MineHud.cs @@ -1,13 +1,13 @@ using System.Collections.Generic; using System.Linq; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using Microsoft.Xna.Framework; using StardewModdingAPI; using StardewValley; using StardewValley.Locations; using StardewValley.Monsters; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { internal class MineHud { diff --git a/JoysOfEfficiency/Huds/MineIcons.cs b/GloryOfEfficiency/Huds/MineIcons.cs similarity index 91% rename from JoysOfEfficiency/Huds/MineIcons.cs rename to GloryOfEfficiency/Huds/MineIcons.cs index eb02a8d..6afd0dd 100644 --- a/JoysOfEfficiency/Huds/MineIcons.cs +++ b/GloryOfEfficiency/Huds/MineIcons.cs @@ -1,11 +1,11 @@ -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { public class MineIcons { @@ -19,11 +19,11 @@ public class MineIcons public static void Init(IModHelper helper) { - _iconPickaxe = helper.Content.Load("icon_pickaxe.png"); - _iconMonster = helper.Content.Load("icon_monster.png"); - _iconLadder = helper.Content.Load("icon_ladder.png"); + _iconPickaxe = helper.ModContent.Load("assets/icon_pickaxe.png"); + _iconMonster = helper.ModContent.Load("assets/icon_monster.png"); + _iconLadder = helper.ModContent.Load("assets/icon_ladder.png"); int x = 16 + OffsetX; - + _logger.Log($"x:{x}"); } diff --git a/JoysOfEfficiency/Huds/PausedHud.cs b/GloryOfEfficiency/Huds/PausedHud.cs similarity index 90% rename from JoysOfEfficiency/Huds/PausedHud.cs rename to GloryOfEfficiency/Huds/PausedHud.cs index 3cfcd34..45a966b 100644 --- a/JoysOfEfficiency/Huds/PausedHud.cs +++ b/GloryOfEfficiency/Huds/PausedHud.cs @@ -1,11 +1,11 @@ -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; using StardewValley; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { internal class PausedHud { diff --git a/JoysOfEfficiency/Huds/ShippingEstimationInfoBox.cs b/GloryOfEfficiency/Huds/ShippingEstimationInfoBox.cs similarity index 95% rename from JoysOfEfficiency/Huds/ShippingEstimationInfoBox.cs rename to GloryOfEfficiency/Huds/ShippingEstimationInfoBox.cs index 86a9ccc..fca1226 100644 --- a/JoysOfEfficiency/Huds/ShippingEstimationInfoBox.cs +++ b/GloryOfEfficiency/Huds/ShippingEstimationInfoBox.cs @@ -1,14 +1,14 @@ using System; using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.Huds +namespace GloryOfEfficiency.Huds { internal class ShippingEstimationInfoBox { diff --git a/JoysOfEfficiency/Menus/JoeMenu.cs b/GloryOfEfficiency/Menus/JoeMenu.cs similarity index 95% rename from JoysOfEfficiency/Menus/JoeMenu.cs rename to GloryOfEfficiency/Menus/JoeMenu.cs index e76876d..f5feb17 100644 --- a/JoysOfEfficiency/Menus/JoeMenu.cs +++ b/GloryOfEfficiency/Menus/JoeMenu.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; -using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.OptionsElements; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.OptionsElements; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -10,7 +9,7 @@ using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.Menus +namespace GloryOfEfficiency.Menus { internal class JoeMenu : IClickableMenu { @@ -86,6 +85,7 @@ internal JoeMenu(int width, int height) tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Balanced Mode")); tab.AddOptionsElement(new ModifiedCheckBox("BalancedMode", 20, Config.BalancedMode, OnCheckboxValueChanged)); + tab.AddOptionsElement(new ModifiedSlider("EveryNthTick", 20, (int)Config.RunEveryNthTick, 5, 60, OnSliderValueChanged, () => Config.BalancedMode)); tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Auto Water Nearby Crops")); @@ -109,7 +109,7 @@ internal JoeMenu(int width, int height) tab.AddOptionsElement(new ModifiedSlider("CPUThresholdFishing", 0, (int)(Config.CpuThresholdFishing * 10), 0, 5, OnSliderValueChanged, () => !Config.AutoFishing, Format)); tab.AddOptionsElement(new ModifiedCheckBox("AutoReelRod", 6, Config.AutoReelRod, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedSlider("ThrowPower", 17, (int)(Config.ThrowPower * 10), 0, 10, OnSliderValueChanged, null, Format)); - tab.AddOptionsElement(new ModifiedSlider("ThresholdStaminaPersentage", 18, Config.ThresholdStaminaPercentage, 10, 60, OnSliderValueChanged, null, Format)); + tab.AddOptionsElement(new ModifiedSlider("ThresholdStaminaPercentage", 18, Config.ThresholdStaminaPercentage, 10, 60, OnSliderValueChanged, null, Format)); tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Auto Gate")); @@ -120,6 +120,7 @@ internal JoeMenu(int width, int height) tab.AddOptionsElement(new ModifiedCheckBox("AutoEat", 10, Config.AutoEat, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedSlider("StaminaToEatRatio", 1, (int)(Config.StaminaToEatRatio * 10), 1, 8, OnSliderValueChanged, () => !Config.AutoEat, Format)); tab.AddOptionsElement(new ModifiedSlider("HealthToEatRatio", 2, (int)(Config.HealthToEatRatio * 10), 1, 8, OnSliderValueChanged, () => !Config.AutoEat, Format)); + tab.AddOptionsElement(new ModifiedCheckBox("DontEatThat", 45, Config.DontEatThat, OnCheckboxValueChanged)); tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Auto Harvest")); @@ -154,6 +155,7 @@ internal JoeMenu(int width, int height) tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Auto Deposit/Pull Machines")); tab.AddOptionsElement(new ModifiedCheckBox("AutoDepositIngredient", 22, Config.AutoDepositIngredient, OnCheckboxValueChanged)); + tab.AddOptionsElement(new ModifiedCheckBox("AutoDepositSeedMaker", 42, Config.AutoDepositSeedMaker, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedCheckBox("AutoPullMachineResult", 23, Config.AutoPullMachineResult, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedSlider("MachineRadius", 10, Config.MachineRadius, 1, 3, OnSliderValueChanged, () => !(Config.AutoPullMachineResult || Config.AutoDepositIngredient) || Config.BalancedMode)); @@ -162,17 +164,17 @@ internal JoeMenu(int width, int height) tab.AddOptionsElement(new ModifiedCheckBox("AutoLootTreasures", 30, Config.AutoLootTreasures, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedCheckBox("CloseTreasureWhenAllLooted", 31, Config.CloseTreasureWhenAllLooted, OnCheckboxValueChanged)); - tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Auto Pick Up Trash")); tab.AddOptionsElement(new ModifiedCheckBox("AutoPickUpTrash", 34, Config.AutoPickUpTrash, OnCheckboxValueChanged)); + tab.AddOptionsElement(new ModifiedCheckBox("GarbageDisgustsNPCs", 46, Config.GarbageDisgustsNPCs, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedSlider("ScavengingRadius", 13, Config.ScavengingRadius, 1, 3, OnSliderValueChanged, () => !Config.AutoPickUpTrash || Config.BalancedMode)); tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Auto Shearing and Milking")); tab.AddOptionsElement(new ModifiedCheckBox("AutoShearingAndMilking", 35, Config.AutoShearingAndMilking, OnCheckboxValueChanged)); tab.AddOptionsElement(new ModifiedSlider("AnimalHarvestRadius", 14, Config.AnimalHarvestRadius, 1, 3, OnSliderValueChanged, () => !Config.AutoShearingAndMilking || Config.BalancedMode)); - + tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Collect Letter Attachments And Quests")); tab.AddOptionsElement(new ModifiedCheckBox("CollectLetterAttachmentsAndQuests", 36, Config.CollectLetterAttachmentsAndQuests, OnCheckboxValueChanged)); @@ -211,10 +213,17 @@ internal JoeMenu(int width, int height) tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Fishing Probabilities Information")); tab.AddOptionsElement(new ModifiedCheckBox("FishingProbabilitiesInfo", 26, Config.FishingProbabilitiesInfo, OnCheckboxValueChanged)); + tab.AddOptionsElement(new ModifiedSlider("ProbBoxMaxFish", 19, Config.ProbBoxMaxFish, 5, 25, OnSliderValueChanged)); tab.AddOptionsElement(new ModifiedClickListener(this, "ProbBoxLocation", 0, Config.ProbBoxCoordinates.X, Config.ProbBoxCoordinates.Y, translation, OnSomewhereClicked, OnStartListeningClick)); tab.AddOptionsElement(new ModifiedCheckBox("MorePreciseProbabilities", 37, Config.MorePreciseProbabilities, OnCheckboxValueChanged, i => !Config.FishingProbabilitiesInfo)); tab.AddOptionsElement(new ModifiedSlider("TrialOfExamine", 15, Config.TrialOfExamine, 1, 50, OnSliderValueChanged, () => !(Config.FishingProbabilitiesInfo && Config.MorePreciseProbabilities))); + tab.AddOptionsElement(new EmptyLabel()); + tab.AddOptionsElement(new LabelComponent("Fishing Tackle Information")); + tab.AddOptionsElement(new ModifiedCheckBox("FishingTackleInfo", 43, Config.FishingTackleInfo, OnCheckboxValueChanged)); + tab.AddOptionsElement(new ModifiedCheckBox("TackleBoxAttach", 44, Config.TackleBoxAttach, OnCheckboxValueChanged)); + tab.AddOptionsElement(new ModifiedClickListener(this, "TackleBoxLocation", 2, Config.TackleBoxCoordinates.X, Config.TackleBoxCoordinates.Y, translation, OnSomewhereClicked, OnStartListeningClick)); + tab.AddOptionsElement(new EmptyLabel()); tab.AddOptionsElement(new LabelComponent("Show Shipping Price")); tab.AddOptionsElement(new ModifiedCheckBox("EstimateShippingPrice", 28, Config.EstimateShippingPrice, OnCheckboxValueChanged)); @@ -295,6 +304,9 @@ private void OnSomewhereClicked(int index, Point point) case 1: Config.PriceBoxCoordinates = point; break; + case 2: + Config.TackleBoxCoordinates = point; + break; default: return; } InstanceHolder.WriteConfig(); @@ -363,6 +375,11 @@ private void OnCheckboxValueChanged(int index, bool value) case 39: Config.CutWeeds = value; break; case 40: Config.BreakRocks = value; break; case 41: Config.ChopTwigs = value; break; + case 42: Config.AutoDepositSeedMaker = value; break; + case 43: Config.FishingTackleInfo = value; break; + case 44: Config.TackleBoxAttach = value; break; + case 45: Config.DontEatThat = value; break; + case 46: Config.GarbageDisgustsNPCs = value; break; default: return; } InstanceHolder.WriteConfig(); @@ -388,6 +405,8 @@ private void OnSliderValueChanged(int index, int value) case 16: Config.RadiusFarmCleanup = value; break; case 17: Config.ThrowPower = value / 10.0f; break; case 18: Config.ThresholdStaminaPercentage = value; break; + case 19: Config.ProbBoxMaxFish = value; break; + case 20: Config.RunEveryNthTick = (uint)value; break; default: return; } @@ -850,7 +869,7 @@ private int GetLastVisibleIndex() } /// - /// Try changing tab to a specified tab. + /// Try changing tab to a specified tab. /// /// Which tab index to change. private void TryToChangeTab(int which) @@ -866,4 +885,4 @@ private void TryToChangeTab(int which) Game1.playSound("drumkit6"); } } -} \ No newline at end of file +} diff --git a/JoysOfEfficiency/Menus/RegisterFlowerMenu.cs b/GloryOfEfficiency/Menus/RegisterFlowerMenu.cs similarity index 96% rename from JoysOfEfficiency/Menus/RegisterFlowerMenu.cs rename to GloryOfEfficiency/Menus/RegisterFlowerMenu.cs index ac94e7c..7fb8bef 100644 --- a/JoysOfEfficiency/Menus/RegisterFlowerMenu.cs +++ b/GloryOfEfficiency/Menus/RegisterFlowerMenu.cs @@ -1,15 +1,15 @@ using System; using System.Collections.Generic; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.OptionsElements; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.OptionsElements; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.Menus +namespace GloryOfEfficiency.Menus { internal class RegisterFlowerMenu : IClickableMenu { @@ -41,7 +41,7 @@ public RegisterFlowerMenu(int width, int height, Color initialColor, int item, A _elements.Add(new EmptyLabel()); if (item != -1) { - string s = string.Format(InstanceHolder.Translation.Get("options.flower"), Util.GetItemName(item)); + string s = string.Format(InstanceHolder.Translation.Get("options.flower"), item.ToString()); _elements.Add(new LabelComponent(s)); _itemIndex = item; } @@ -74,7 +74,7 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) } y -= element.bounds.Height + MARGIN_COMPONENTS; } - + } public override void leftClickHeld(int x, int y) diff --git a/JoysOfEfficiency/Misc/IdlePause.cs b/GloryOfEfficiency/Misc/IdlePause.cs similarity index 92% rename from JoysOfEfficiency/Misc/IdlePause.cs rename to GloryOfEfficiency/Misc/IdlePause.cs index cdd82bb..0037aee 100644 --- a/JoysOfEfficiency/Misc/IdlePause.cs +++ b/GloryOfEfficiency/Misc/IdlePause.cs @@ -1,9 +1,9 @@ -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Huds; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Huds; +using GloryOfEfficiency.Utils; using StardewValley; -namespace JoysOfEfficiency.Misc +namespace GloryOfEfficiency.Misc { internal class IdlePause { diff --git a/JoysOfEfficiency/ModCheckers/ModChecker.cs b/GloryOfEfficiency/ModCheckers/ModChecker.cs similarity index 87% rename from JoysOfEfficiency/ModCheckers/ModChecker.cs rename to GloryOfEfficiency/ModCheckers/ModChecker.cs index fa46bf0..a4f4e5b 100644 --- a/JoysOfEfficiency/ModCheckers/ModChecker.cs +++ b/GloryOfEfficiency/ModCheckers/ModChecker.cs @@ -1,6 +1,6 @@ using StardewModdingAPI; -namespace JoysOfEfficiency.ModCheckers +namespace GloryOfEfficiency.ModCheckers { public class ModChecker { diff --git a/JoysOfEfficiency/OptionsElements/ButtonWithLabel.cs b/GloryOfEfficiency/OptionsElements/ButtonWithLabel.cs similarity index 94% rename from JoysOfEfficiency/OptionsElements/ButtonWithLabel.cs rename to GloryOfEfficiency/OptionsElements/ButtonWithLabel.cs index e8ef225..d860822 100644 --- a/JoysOfEfficiency/OptionsElements/ButtonWithLabel.cs +++ b/GloryOfEfficiency/OptionsElements/ButtonWithLabel.cs @@ -1,11 +1,11 @@ using System; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class ButtonWithLabel : OptionsElement { @@ -15,7 +15,7 @@ internal class ButtonWithLabel : OptionsElement private readonly Func _isDisabled; public ButtonWithLabel(string label, int which, - Action onButtonPressed = null, Func isDisabled = null) + Action onButtonPressed = null, Func isDisabled = null) : base(label, -1, -1, 9 * Game1.pixelZoom, 9 * Game1.pixelZoom, which) { this.label = InstanceHolder.Translation.Get($"options.{label}"); @@ -26,7 +26,7 @@ public ButtonWithLabel(string label, int which, public override void receiveLeftClick(int x, int y) { base.receiveLeftClick(x, y); - + if (x >= _buttonRect.Left && x <= _buttonRect.Right) { _onButtonPressed(whichOption); diff --git a/JoysOfEfficiency/OptionsElements/ColorBox.cs b/GloryOfEfficiency/OptionsElements/ColorBox.cs similarity index 95% rename from JoysOfEfficiency/OptionsElements/ColorBox.cs rename to GloryOfEfficiency/OptionsElements/ColorBox.cs index 5f3545e..d2a2ce2 100644 --- a/JoysOfEfficiency/OptionsElements/ColorBox.cs +++ b/GloryOfEfficiency/OptionsElements/ColorBox.cs @@ -1,9 +1,9 @@ -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class ColorBox : OptionsElement { diff --git a/JoysOfEfficiency/OptionsElements/EmptyLabel.cs b/GloryOfEfficiency/OptionsElements/EmptyLabel.cs similarity index 86% rename from JoysOfEfficiency/OptionsElements/EmptyLabel.cs rename to GloryOfEfficiency/OptionsElements/EmptyLabel.cs index fbb4094..7d63a86 100644 --- a/JoysOfEfficiency/OptionsElements/EmptyLabel.cs +++ b/GloryOfEfficiency/OptionsElements/EmptyLabel.cs @@ -1,7 +1,7 @@ using Microsoft.Xna.Framework.Graphics; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class EmptyLabel : LabelComponent { diff --git a/JoysOfEfficiency/OptionsElements/LabelComponent.cs b/GloryOfEfficiency/OptionsElements/LabelComponent.cs similarity index 92% rename from JoysOfEfficiency/OptionsElements/LabelComponent.cs rename to GloryOfEfficiency/OptionsElements/LabelComponent.cs index a5adf58..6558db1 100644 --- a/JoysOfEfficiency/OptionsElements/LabelComponent.cs +++ b/GloryOfEfficiency/OptionsElements/LabelComponent.cs @@ -3,7 +3,7 @@ using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class LabelComponent : OptionsElement { diff --git a/JoysOfEfficiency/OptionsElements/MenuTab.cs b/GloryOfEfficiency/OptionsElements/MenuTab.cs similarity index 91% rename from JoysOfEfficiency/OptionsElements/MenuTab.cs rename to GloryOfEfficiency/OptionsElements/MenuTab.cs index 14270be..dc868dd 100644 --- a/JoysOfEfficiency/OptionsElements/MenuTab.cs +++ b/GloryOfEfficiency/OptionsElements/MenuTab.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class MenuTab { diff --git a/JoysOfEfficiency/OptionsElements/ModifiedCheckBox.cs b/GloryOfEfficiency/OptionsElements/ModifiedCheckBox.cs similarity index 95% rename from JoysOfEfficiency/OptionsElements/ModifiedCheckBox.cs rename to GloryOfEfficiency/OptionsElements/ModifiedCheckBox.cs index f0f33b4..7e579c7 100644 --- a/JoysOfEfficiency/OptionsElements/ModifiedCheckBox.cs +++ b/GloryOfEfficiency/OptionsElements/ModifiedCheckBox.cs @@ -1,11 +1,11 @@ using System; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class ModifiedCheckBox : OptionsElementWithLabel { diff --git a/JoysOfEfficiency/OptionsElements/ModifiedClickListener.cs b/GloryOfEfficiency/OptionsElements/ModifiedClickListener.cs similarity index 97% rename from JoysOfEfficiency/OptionsElements/ModifiedClickListener.cs rename to GloryOfEfficiency/OptionsElements/ModifiedClickListener.cs index 8b01b79..c5cd5a5 100644 --- a/JoysOfEfficiency/OptionsElements/ModifiedClickListener.cs +++ b/GloryOfEfficiency/OptionsElements/ModifiedClickListener.cs @@ -1,6 +1,6 @@ using System; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Core; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -8,7 +8,7 @@ using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class ModifiedClickListener : OptionsElement { diff --git a/JoysOfEfficiency/OptionsElements/ModifiedInputListener.cs b/GloryOfEfficiency/OptionsElements/ModifiedInputListener.cs similarity index 98% rename from JoysOfEfficiency/OptionsElements/ModifiedInputListener.cs rename to GloryOfEfficiency/OptionsElements/ModifiedInputListener.cs index 7d793bf..9bc5b34 100644 --- a/JoysOfEfficiency/OptionsElements/ModifiedInputListener.cs +++ b/GloryOfEfficiency/OptionsElements/ModifiedInputListener.cs @@ -1,5 +1,5 @@ using System; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -7,7 +7,7 @@ using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class ModifiedInputListener : OptionsElement { diff --git a/JoysOfEfficiency/OptionsElements/ModifiedSlider.cs b/GloryOfEfficiency/OptionsElements/ModifiedSlider.cs similarity index 97% rename from JoysOfEfficiency/OptionsElements/ModifiedSlider.cs rename to GloryOfEfficiency/OptionsElements/ModifiedSlider.cs index 3e0b5ee..08c433e 100644 --- a/JoysOfEfficiency/OptionsElements/ModifiedSlider.cs +++ b/GloryOfEfficiency/OptionsElements/ModifiedSlider.cs @@ -1,11 +1,11 @@ using System; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewValley; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { internal class ModifiedSlider : OptionsElementWithLabel { diff --git a/JoysOfEfficiency/OptionsElements/OptionsElementWithLabel.cs b/GloryOfEfficiency/OptionsElements/OptionsElementWithLabel.cs similarity index 89% rename from JoysOfEfficiency/OptionsElements/OptionsElementWithLabel.cs rename to GloryOfEfficiency/OptionsElements/OptionsElementWithLabel.cs index cbc77cb..7521bb1 100644 --- a/JoysOfEfficiency/OptionsElements/OptionsElementWithLabel.cs +++ b/GloryOfEfficiency/OptionsElements/OptionsElementWithLabel.cs @@ -1,8 +1,8 @@ -using JoysOfEfficiency.Utils; +using GloryOfEfficiency.Utils; using Microsoft.Xna.Framework.Graphics; using StardewValley.Menus; -namespace JoysOfEfficiency.OptionsElements +namespace GloryOfEfficiency.OptionsElements { public abstract class OptionsElementWithLabel : OptionsElement { diff --git a/JoysOfEfficiency/Properties/AssemblyInfo.cs b/GloryOfEfficiency/Properties/AssemblyInfo.cs similarity index 88% rename from JoysOfEfficiency/Properties/AssemblyInfo.cs rename to GloryOfEfficiency/Properties/AssemblyInfo.cs index 0017fc6..a68bebe 100644 --- a/JoysOfEfficiency/Properties/AssemblyInfo.cs +++ b/GloryOfEfficiency/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 // アセンブリに関連付けられている情報を変更するには、 // これらの属性値を変更してください。 -[assembly: AssemblyTitle("JoysOfEfficiency")] +[assembly: AssemblyTitle("GloryOfEfficiency")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("JoysOfEfficiency")] -[assembly: AssemblyCopyright("Copyright yakminepunyo© 2018")] +[assembly: AssemblyProduct("GloryOfEfficiency")] +[assembly: AssemblyCopyright("Copyright yakminepunyo© 2018, Copyright Hackswell© 2024")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/JoysOfEfficiency/Properties/Resources.Designer.cs b/GloryOfEfficiency/Properties/Resources.Designer.cs similarity index 96% rename from JoysOfEfficiency/Properties/Resources.Designer.cs rename to GloryOfEfficiency/Properties/Resources.Designer.cs index a1a6e95..51c4cf4 100644 --- a/JoysOfEfficiency/Properties/Resources.Designer.cs +++ b/GloryOfEfficiency/Properties/Resources.Designer.cs @@ -16,7 +16,7 @@ using System.Resources; using System.Runtime.CompilerServices; -namespace JoysOfEfficiency.Properties { +namespace GloryOfEfficiency.Properties { /// /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 /// @@ -44,7 +44,7 @@ internal Resources() { internal static ResourceManager ResourceManager { get { if (ReferenceEquals(resourceMan, null)) { - ResourceManager temp = new ResourceManager("JoysOfEfficiency.Properties.Resources", typeof(Resources).Assembly); + ResourceManager temp = new ResourceManager("GloryOfEfficiency.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; diff --git a/JoysOfEfficiency/Properties/Resources.resx b/GloryOfEfficiency/Properties/Resources.resx similarity index 100% rename from JoysOfEfficiency/Properties/Resources.resx rename to GloryOfEfficiency/Properties/Resources.resx diff --git a/JoysOfEfficiency/Utils/ConfigHolder.cs b/GloryOfEfficiency/Utils/ConfigHolder.cs similarity index 81% rename from JoysOfEfficiency/Utils/ConfigHolder.cs rename to GloryOfEfficiency/Utils/ConfigHolder.cs index b5ef312..369cae7 100644 --- a/JoysOfEfficiency/Utils/ConfigHolder.cs +++ b/GloryOfEfficiency/Utils/ConfigHolder.cs @@ -1,7 +1,7 @@ using System.IO; -using Newtonsoft.Json; +using System.Text.Json; -namespace JoysOfEfficiency.Utils +namespace GloryOfEfficiency.Utils { public abstract class ConfigHolder { @@ -29,12 +29,12 @@ protected void Load() Logger.Log("Loaded "+ _configFileName); string jsonContent = File.ReadAllText(_configFileName); - Entry = JsonConvert.DeserializeObject(jsonContent); + Entry = JsonSerializer.Deserialize(jsonContent); } public void Save() { - string jsonContent = JsonConvert.SerializeObject(Entry, Formatting.Indented); + string jsonContent = JsonSerializer.Serialize(Entry); File.WriteAllText(_configFileName, jsonContent); Logger.Log("Saved " + Path.GetFullPath(_configFileName)); } diff --git a/JoysOfEfficiency/Utils/CustomAnimalConfigHolder.cs b/GloryOfEfficiency/Utils/CustomAnimalConfigHolder.cs similarity index 82% rename from JoysOfEfficiency/Utils/CustomAnimalConfigHolder.cs rename to GloryOfEfficiency/Utils/CustomAnimalConfigHolder.cs index 69711ad..02fc390 100644 --- a/JoysOfEfficiency/Utils/CustomAnimalConfigHolder.cs +++ b/GloryOfEfficiency/Utils/CustomAnimalConfigHolder.cs @@ -1,6 +1,6 @@ -using JoysOfEfficiency.Configs; +using GloryOfEfficiency.Configs; -namespace JoysOfEfficiency.Utils +namespace GloryOfEfficiency.Utils { internal class CustomAnimalConfigHolder : ConfigHolder { diff --git a/JoysOfEfficiency/Utils/Logger.cs b/GloryOfEfficiency/Utils/Logger.cs similarity index 78% rename from JoysOfEfficiency/Utils/Logger.cs rename to GloryOfEfficiency/Utils/Logger.cs index 9f9538f..8ff64fc 100644 --- a/JoysOfEfficiency/Utils/Logger.cs +++ b/GloryOfEfficiency/Utils/Logger.cs @@ -1,13 +1,12 @@ using StardewModdingAPI; -namespace JoysOfEfficiency.Utils +namespace GloryOfEfficiency.Utils { public class Logger { public static IMonitor Monitor { get; private set; - } public static void Init(IMonitor monitor) @@ -26,6 +25,11 @@ public void Log(string text, LogLevel level = LogLevel.Trace) Monitor.Log($"[{Name}]{text}", level); } + public void Info(string text, LogLevel level = LogLevel.Info) + { + Monitor.Log($"[{Name}]{text}", level); + } + public void Error(string text) { Log(text, LogLevel.Error); diff --git a/JoysOfEfficiency/Utils/Util.cs b/GloryOfEfficiency/Utils/Util.cs similarity index 86% rename from JoysOfEfficiency/Utils/Util.cs rename to GloryOfEfficiency/Utils/Util.cs index 347f5b3..47db312 100644 --- a/JoysOfEfficiency/Utils/Util.cs +++ b/GloryOfEfficiency/Utils/Util.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using JoysOfEfficiency.Core; +using GloryOfEfficiency.Core; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; using StardewValley; -using StardewValley.Locations; using StardewValley.Menus; using StardewValley.TerrainFeatures; using StardewValley.Tools; @@ -14,7 +13,7 @@ using static StardewValley.Game1; using Object = StardewValley.Object; -namespace JoysOfEfficiency.Utils +namespace GloryOfEfficiency.Utils { using Player = Farmer; using SVObject = Object; @@ -22,8 +21,6 @@ internal class Util { private static ITranslationHelper Translation => InstanceHolder.Translation; private static Config Config => InstanceHolder.Config; - - private static int _lastItemIndex; public static bool IsAndroid() @@ -31,11 +28,6 @@ public static bool IsAndroid() return Constants.TargetPlatform == GamePlatform.Android; } - public static string GetItemName(int parentSheetIndex) - { - return new SVObject(parentSheetIndex, 1).DisplayName; - } - public static T FindToolFromInventory(bool fromEntireInventory) where T : Tool { Player player = Game1.player; @@ -61,7 +53,7 @@ public static float Cap(float f, float min, float max) return f < min ? min : (f > max ? max : f); } - + public static void ShowHudMessage(string message, int duration = 3500) { @@ -78,26 +70,6 @@ public static void ShowHudMessageTranslated(string key, int duration = 3500) ShowHudMessage(Translation.Get(key), duration); } - public static IEnumerable GetAnimalsList(Character player) - { - List list = new List(); - switch (player.currentLocation) - { - case Farm farm: - { - list.AddRange(farm.animals.Values); - break; - } - - case AnimalHouse house: - { - list.AddRange(house.animals.Values); - break; - } - } - return list; - } - public static Rectangle Expand(Rectangle rect, int radius) { return new Rectangle(rect.Left - radius, rect.Top - radius, 2 * radius, 2 * radius); @@ -159,7 +131,10 @@ public static bool IsThereAnyWaterNear(GameLocation location, Vector2 tileLocati { Vector2 toCheck = tileLocation + new Vector2(i, j); int x = (int)toCheck.X, y = (int)toCheck.Y; - if (location.doesTileHaveProperty(x, y, "Water", "Back") != null || location.doesTileHaveProperty(x, y, "WaterSource", "Back") != null || location is BuildableGameLocation loc2 && loc2.buildings.Where(b => b.occupiesTile(toCheck)).Any(building => building.buildingType.Value == "Well")) + if (location.doesTileHaveProperty(x, y, "Water", "Back") != null + || location.doesTileHaveProperty(x, y, "WaterSource", "Back") != null + || location.IsBuildableLocation() + && location.buildings.Where(b => b.occupiesTile(toCheck)).Any(building => building.buildingType.Value == "Well")) { return true; } @@ -179,9 +154,10 @@ public static T FindToolFromInventory(Player player, bool findFromInventory) public static List GetObjectsWithin(int radius, bool ignoreBalancedMode = false) where T : SVObject { + List list = new List(); if (!Context.IsWorldReady || currentLocation?.Objects == null) { - return new List(); + return list; } if (InstanceHolder.Config.BalancedMode && !ignoreBalancedMode) { @@ -189,17 +165,13 @@ public static List GetObjectsWithin(int radius, bool ignoreBalancedMode = } GameLocation location = player.currentLocation; - Vector2 ov = player.getTileLocation(); - List list = new List(); + Vector2 ov = player.Tile; for (int dx = -radius; dx <= radius; dx++) { for (int dy = -radius; dy <= radius; dy++) { - Vector2 loc = ov + new Vector2(dx, dy); - if (location.Objects.ContainsKey(loc) && location.Objects[loc] is T t) - { - list.Add(t); - } + location.Objects.TryGetValue(ov + new Vector2(dx, dy), out Object obj); + if (obj is T t) list.Add(t); } } return list; @@ -289,28 +261,29 @@ public static int GetMaxCan(WateringCan can) { if (can == null) return -1; + int waterCanSize; switch (can.UpgradeLevel) { case 0: - can.waterCanMax = 40; + waterCanSize = 40; break; case 1: - can.waterCanMax = 55; + waterCanSize = 55; break; case 2: - can.waterCanMax = 70; + waterCanSize = 70; break; case 3: - can.waterCanMax = 85; + waterCanSize= 85; break; case 4: - can.waterCanMax = 100; + waterCanSize = 100; break; default: return -1; } - return can.waterCanMax; + return waterCanSize; } @@ -336,14 +309,13 @@ public static Dictionary GetFeaturesWithin(int radius) where T : radius = 1; } GameLocation location = player.currentLocation; - Vector2 ov = player.getTileLocation(); Dictionary list = new Dictionary(); for (int dx = -radius; dx <= radius; dx++) { for (int dy = -radius; dy <= radius; dy++) { - Vector2 loc = ov + new Vector2(dx, dy); + Vector2 loc = player.Tile + new Vector2(dx, dy); if (location.terrainFeatures.ContainsKey(loc) && location.terrainFeatures[loc] is T t) { list.Add(loc, t); @@ -358,12 +330,6 @@ public static Vector2 GetLocationOf(GameLocation location, SVObject obj) return location.Objects.Pairs.Any(kv => kv.Value == obj) ? location.Objects.Pairs.First(kv => kv.Value == obj).Key : new Vector2(-1, -1); } - - - - - - private static void DrawItemPickupHud(Item item) { @@ -393,7 +359,7 @@ private static void DrawItemPickupHud(Item item) } } - addHUDMessage(new HUDMessage(text, Math.Max(1, item.Stack), true, color, item)); + addHUDMessage(new HUDMessage(text, 3.0f, true)); } public static int GetTruePrice(Item item) diff --git a/JoysOfEfficiency/WhatsNew.md b/GloryOfEfficiency/WhatsNew.md similarity index 72% rename from JoysOfEfficiency/WhatsNew.md rename to GloryOfEfficiency/WhatsNew.md index 02ced2b..9616be3 100644 --- a/JoysOfEfficiency/WhatsNew.md +++ b/GloryOfEfficiency/WhatsNew.md @@ -1,7 +1,54 @@ # Overview -This is a changelog from 1.0.22 +This is a changelog from 1.5.0 # Changelog +## 1.5.0 +- Update build files to work with net6.0 / SdV 1.6 [Hackswell + others] + - Removed all Reflections and use updated public methods + - Converted all ObjectIDs from Int32 to string. Still unoptimized, but should be more compatible. +- Added config option "AutoDepositSeedMaker" to NOT auto-drop into Seed Makers. [Hackswell] +- Added new config item "MachineTypes" in config.json. [Hackswell] + - All machines are enumerated by default now, and up to date as of SdV 1.6.4. + - If a new machine is added to SdV, you can manually add the name to the list. No need to recompile JoE! +- Added new config item "RunEveryNthTick". If BalancedMode is FALSE, then run the JoE loops every "RunEveryNthTick"/60.0 seconds. +- Updated some of the Fishing HUDs and probability code. [Sandman534] + - New config items: + - FishingTackleInfo: true / FALSE [default] + - TackleBoxAttach: true / FALSE [default] + - TackleBoxCoordinates: [x, y] + - ProbMaxFish: 10 [maximum number of probabilities to list] +- Added code from "Don't Eat This" mod by [Pyrohead37]. Module hasn't been updated since 2019. + - New config items, loaded in this order: + - DontEatThat: true / FALSE [default] + - DontEatCategories: Which categories of items NOT to eat. Defaults are: + - Artisan Goods + - Animal Product + - Crop + - Fish + - Flower + - Harmful + - Vegetable + - DontEat: Which specific ITEMS not to eat. It's okay if they overlap categories. Defaults: + - Holly + - Oil + - Red Mushroom + - Sap + - Truffle + - DoEat: Which specific ITEMS to ALLOW eating. These are actually _removed_ from the "don't eat" list that was compiled from the above entries. Defaults: + - Mayonnaise + - Beer + - Green Tea +- Removed heaps of antiquated code from SdV 1.3/1.4 [Hackswell] +- May still contain inefficient algorithms. Still need to modernize some of the loops with "newly" available methods. + + +## 1.4.9 +- Updated build files to work with net5.0 +- Updated code to work with HarmonyLib +- Moved from Newtonsoft.Json to System.Text.Json +- Reduce number of warnings +- Added Heavy Tapper to machine list for auto-collection +- Added new option to NOT auto-add to Seed Makers ## 1.0.22 - Moved Utilities to Util.cs diff --git a/JoysOfEfficiency/Arts/icon_ladder.png b/GloryOfEfficiency/assets/icon_ladder.png similarity index 100% rename from JoysOfEfficiency/Arts/icon_ladder.png rename to GloryOfEfficiency/assets/icon_ladder.png diff --git a/JoysOfEfficiency/Arts/icon_monster.png b/GloryOfEfficiency/assets/icon_monster.png similarity index 100% rename from JoysOfEfficiency/Arts/icon_monster.png rename to GloryOfEfficiency/assets/icon_monster.png diff --git a/JoysOfEfficiency/Arts/icon_pickaxe.png b/GloryOfEfficiency/assets/icon_pickaxe.png similarity index 100% rename from JoysOfEfficiency/Arts/icon_pickaxe.png rename to GloryOfEfficiency/assets/icon_pickaxe.png diff --git a/JoysOfEfficiency/i18n/de.json b/GloryOfEfficiency/i18n/de.json similarity index 94% rename from JoysOfEfficiency/i18n/de.json rename to GloryOfEfficiency/i18n/de.json index de21950..933dd38 100644 --- a/JoysOfEfficiency/i18n/de.json +++ b/GloryOfEfficiency/i18n/de.json @@ -45,6 +45,10 @@ "options.FishInfo": "Zeige stets die Infobox fürs Fischen", "options.FishingInfo": "Zeigt die Infobox beim Fischen", "options.FishingProbabilitiesInfo": "Zeige die Wahrscheinlichkeit der Fische", + "options.FishingTackleInfo": "Ziehen Sie aktuelle Köder und Bobber", + "options.TackleBoxAttach": "Befestigen Sie die Angelbox an der Fischwahrscheinlichkeitsbox", + "options.TackleBoxLocation": "Koordinaten oben links für das Informationsfeld", + "options.ProbBoxMaxFish": "Anzahl der Fische pro Spalte", "options.GiftInformation": "Zeige den Tooltip für Geschenke", "options.HealthToEatRatio": "Automatisches Essen, um Gesundheit aufzufüllent", "options.IdleTimeout": "Leerlauf-Timeout für das Pausieren des Spiels", diff --git a/JoysOfEfficiency/i18n/default.json b/GloryOfEfficiency/i18n/default.json similarity index 88% rename from JoysOfEfficiency/i18n/default.json rename to GloryOfEfficiency/i18n/default.json index 7fc86cf..b0f8aa0 100644 --- a/JoysOfEfficiency/i18n/default.json +++ b/GloryOfEfficiency/i18n/default.json @@ -26,11 +26,12 @@ "options.AutoCollectCollectibles": "Auto-collect collectibles nearby", "options.AutoCollectRadius": "How far tiles to auto-collect", "options.AutoDepositIngredient": "Deposit ingredient you held to machines", + "options.AutoDepositSeedMaker": " Deposit ingredient to Seed Makers", "options.AutoDestroyDeadCrops": "Auto-destroy dead crops nearby", "options.AutoDigArtifactSpot": "Auto-dig nearby artifact spots", "options.AutoDigRadius": "How far tiles to auto-dig", "options.AutoEat": "Auto-eat something if in the pinch", - "options.AutoFishing": "Automatic Fishing minigame", + "options.AutoFishing": "Automatic Fishing mini-game", "options.AutoGate": "Open/Close gates automatically", "options.AutoHarvest": "Auto-Harvest grown crops", "options.AutoHarvestRadius": "How far tiles to harvest", @@ -39,6 +40,7 @@ "options.AutoPetNearbyPets": "Auto-pet nearby pets", "options.AutoPetRadius": "How far tiles to find animals", "options.AutoPickUpTrash": "Scavenges nearby trash can", + "options.GarbageDisgustsNPCs": "Scavenging garbage disgusts NPCs", "options.AutoPullMachineResult": "Auto-pull results from machines", "options.AutoReelRod": "Auto reeling when fish nibbled", "options.AutoRefillWateringCan": "Auto-refill watering can near water", @@ -47,11 +49,13 @@ "options.AutoShearingAndMilking": "Auto-shear/milk mature sheep/cows", "options.AutoWaterNearbyCrops": "Automatic Watering to crops", "options.AutoWaterRadius": "How far tiles to be watered", - "options.BalancedMode": "Toggle Balanced Mode", + "options.BalancedMode": "Balanced Mode (JoE once per second limit)", + "options.EveryNthTick": "Update Every Nth Tick", "options.CloseTreasureWhenAllLooted": "Close treasure box when all items taken", "options.CollectLetterAttachmentsAndQuests": "Auto-accept quests or item attached to mail", "options.CPUThresholdFishing": "How often AI operates bar", "options.CraftingFromChests": "Crafting using items in nearby chests", + "options.DontEatThat": "Enable 'Don't Eat That(tm)'", "options.EstimateShippingPrice": "Estimate Shipping Price", "options.FilterBackgroundInMenu": "Outside of config menu will be darker", "options.FindCanFromInventory": "Find Watering Can from inventory", @@ -59,6 +63,7 @@ "options.FishInfo": "Draw fish information box", "options.FishingInfo": "Draw fish information box", "options.FishingProbabilitiesInfo": "Draw probabilities of fishing", + "options.ThresholdStaminaPercentage": "Percent Stamina Threshold", "options.GiftInformation": "Shows Gift Information Tooltips", "options.HealthToEatRatio": "Health Threshold to auto-eat", "options.IdleTimeout": "Idle timeout for pausing the game", @@ -84,15 +89,20 @@ "options.ChopTwigs": "Chop twigs (Axe)", "options.PriceBoxCoordinates": "Top-left coordinates for the information box", + "options.FishingTackleInfo": "Draw current bait and bobbers", + "options.TackleBoxAttach": "Attach the tackle box to fish probabilities box", + "options.TackleBoxLocation": "Top-left coordinates for the information box", + "options.ProbBoxMaxFish": "Number of fish per column", + "options.ThrowPower": "Bobber throwing strength", "options.ThresholdStaminaPersentage": "Stamina threshold to stop fishing", - "options.ToggleAFKFishing": "Toggle AFK Fishing mode", + "options.ToggleAFKFishing": "Toggle AFK Fishing mode", "hud.afk.passedout": "You stopped fishing because you passed out.", "hud.afk.on": "AFK Fishing enabled.", "hud.afk.off": "AFK Fishing disabled.", - "hud.afk.tired": "You stopped fishing because you felt tired.", + "hud.afk.tired": "You stopped fishing because you felt tired.", "options.flower": "Flower:{0}", "options.R": "R", @@ -131,4 +141,4 @@ "taste.love.male": "He loves this gift.", "taste.neutral.female": "She has neutral feelings about this gift.", "taste.neutral.male": "He has neutral feelings about this gift." -} \ No newline at end of file +} diff --git a/JoysOfEfficiency/i18n/es.json b/GloryOfEfficiency/i18n/es.json similarity index 90% rename from JoysOfEfficiency/i18n/es.json rename to GloryOfEfficiency/i18n/es.json index 8f2846b..d1e0d42 100644 --- a/JoysOfEfficiency/i18n/es.json +++ b/GloryOfEfficiency/i18n/es.json @@ -16,6 +16,7 @@ "options.AutoCollectCollectibles": "Colecciona objetos de colección en las cercanías", "options.AutoCollectRadius": "Azulejos para coleccionar", "options.AutoDepositIngredient": "Deposite el ingrediente que aferró a las máquinas", + "options.AutoDepositSeedMaker": "\tDeposite el ingrediente en los Seed Makers", "options.AutoDestroyDeadCrops": "Destruir las cosechas muertas cercanas", "options.AutoDigArtifactSpot": "Cavando un artefacto cercano", "options.AutoDigRadius": "Baldosas para excavación", @@ -37,6 +38,7 @@ "options.AutoWaterNearbyCrops": "Riego automático a cultivos", "options.AutoWaterRadius": "Baldosas para regar", "options.BalancedMode": "Alternar el modo balanceado", + "options.EveryNthTick": "Actualizar cada N Ticks", "options.CloseTreasureWhenAllLooted": "Cerrar la caja del tesoro cuando haya robado todo", "options.CPUThresholdFishing": "Con qué frecuencia AI opera la barra", "options.CraftingFromChests": "Artesanías de los cofres cercanos", @@ -46,6 +48,10 @@ "options.FishInfo": "Dibujar información de peces", "options.FishingInfo": "Dibujar el cuadro de información de pesca", "options.FishingProbabilitiesInfo": "Dibujar probabilidades de pesca", + "options.FishingTackleInfo": "Dibujar cebos y bobbers actuales", + "options.TackleBoxAttach": "Adjunte la caja de aparejos a la caja de probabilidades de pescar.", + "options.TackleBoxLocation": "Coordenadas superior izquierda para el cuadro de información.", + "options.ProbBoxMaxFish": "Número de peces por columna", "options.GiftInformation": "Mostrar información de regalos", "options.HealthToEatRatio": "Salud para comer auto", "options.IdleTimeout": "Tiempo de espera para pausar el juego", @@ -60,6 +66,7 @@ "options.ScavengingRadius": "Qué tan lejos las baldosas para buscarlo", "options.StaminaToEatRatio": "Resistencia para comer auto", "options.UnifyFlowerColors": "Unificar los colores de las flores", + "options.DontEatThat": "Habilitar 'No Comas Eso(tm)'", "quality.gold": "Oro", "quality.iridium": "Iridium", "quality.normal": "Normal", @@ -81,4 +88,4 @@ "taste.love.male": "Él ama este regalo", "taste.neutral.female": "Ella tiene un sentimiento neutral acerca de este regalo", "taste.neutral.male": "Él tiene un sentimiento neutral acerca de este regalo" -} \ No newline at end of file +} diff --git a/GloryOfEfficiency/i18n/fr.json b/GloryOfEfficiency/i18n/fr.json new file mode 100644 index 0000000..8a3cf1a --- /dev/null +++ b/GloryOfEfficiency/i18n/fr.json @@ -0,0 +1,130 @@ +{ + "button.awaiting": "Appuyez sur la touche ou le bouton pour l'assigner...", + "button.conflict": "La touche ou le bouton que vous avez pressé est déjà utilisée.", + "button.esc": "Appuyez sur la touche Échap pour annuler", + "estimatedprice.title": "Prix de vente estimé", + "fishinfo.quality": "Qualité :", + "fishinfo.size": "Taille : {0} pouce(s)", + "fishinfo.species": "Espèce : {0}", + "fishinfo.treasure.appear": "Trésor apparu !", + "fishinfo.treasure.caught": "Trésor attrapé !", + "fishinfo.treasure.incoming": "Un trésor apparaîtra dans {0:f1} s.", + "fishinfo.price": "Prix de vente : {0} po", + "hud.paused": "Jeu en pause.", + "ladder": "L'échelle est apparue !", + "location.awaiting": "Cliquez quelque part pour désigner l'emplacement que vous voulez.", + "monsters.tally": "{0} : {1} éliminés", + "options.AnimalHarvestRadius": "Distance des animaux (cases) ", + "options.AutoAnimalDoor": "Auto-ouverture/fermeture des portes des animaux", + "options.AutoCollectCollectibles": "Auto-ramassage des objets récoltables proches", + "options.AutoCollectRadius": "Distance de ramassage (cases) ", + "options.AutoDepositIngredient": "Auto-dépôt d’ingrédients dans les machines", + "options.AutoDepositSeedMaker": "Auto-dépôt d’ingrédients dans les extracteurs de graines", + "options.AutoDestroyDeadCrops": "Auto-destruction des cultures mortes proches", + "options.AutoDigArtifactSpot": "Auto-creusage des sites d'artéfacts proches", + "options.AutoDigRadius": "Distance de creusage auto (cases) ", + "options.AutoEat": "Auto-consommer quelque chose en cas de besoin", + "options.AutoFishing": "Pêche automatique", + "options.AutoGate": "Auto-ouverture/fermeture des portails", + "options.AutoHarvest": "Auto-récolte des cultures mûres", + "options.AutoHarvestRadius": "Distance de récolte (cases) ", + "options.AutoLootTreasures": "Auto-ramassage des objets des boîtes à trésors", + "options.AutoPetNearbyAnimals": "Auto-caresse des animaux proches", + "options.AutoPetNearbyPets": "Auto-caresse des animaux de compagnie proches", + "options.AutoPetRadius": "Distance des animaux (cases) ", + "options.AutoPickUpTrash": "Auto-ramassage des déchets à proximité", + "options.AutoPullMachineResult": "Auto-récupération des résultats des machines", + "options.AutoReelRod": "Auto-rembobinage lorsqu'un poisson mord", + "options.AutoRefillWateringCan": "Auto-rechargement de l’arrosoir près de l'eau", + "options.AutoShakeFruitedPlants": "Auto-secouage des plantes fruitières à proximité", + "options.AutoShakeRadius": "Distance de secouage auto (cases) ", + "options.AutoShearingAndMilking": "Auto-tondre/traire les moutons/vaches matures", + "options.AutoWaterNearbyCrops": "Auto-arrosage des cultures", + "options.AutoWaterRadius": "Distance d'arrosage (cases) ", + "options.BalancedMode": "Mode équilibré (limiter JoE à 1x /seconde)", + "options.EveryNthTick": "Mise à jour tous les N ticks ", + "options.CloseTreasureWhenAllLooted": "Fermer la boîte à trésor lorsque tous les objets sont pris", + "options.CollectLetterAttachmentsAndQuests": "Auto-acceptation quêtes et pièces jointes des courriers", + "options.CPUThresholdFishing": "Fréquence de l’actualisation de l’IA", + "options.CraftingFromChests": "Fabrication en utilisant les objets dans les coffres proches", + "options.DontEatThat": "Activer \"Ne mange pas ça (©)\"", + "options.EstimateShippingPrice": "Estimer le prix d'expédition", + "options.FilterBackgroundInMenu": "Arrière-plan assombri en dehors du menu de config.", + "options.FindCanFromInventory": "Équiper l'arrosoir dans l'inventaire", + "options.FindHoeFromInventory": "Équiper la houe dans l'inventaire", + "options.FishInfo": "Afficher la boîte d'information sur le poisson", + "options.FishingInfo": "Afficher la boîte d'information sur la pêche", + "options.FishingProbabilitiesInfo": "Afficher les probabilités de pêche", + "options.ThresholdStaminaPercentage": "Pourcentage de seuil de stamina", + "options.GiftInformation": "Afficher les info-bulles sur les cadeaux", + "options.HealthToEatRatio": "Seuil santé pour l’auto-conso ", + "options.IdleTimeout": "Délai d'inactivité avant pause ", + "options.KeyShowMenu": "Afficher le menu des paramètres ", + "options.KeyToggleBlackList": "Activer/désactiver la liste noire de récolte ", + "options.MachineRadius": "Distance des machines (cases) ", + "options.MineInfoGui": "Afficher les icônes d'information dans les mines", + "options.MuchFasterBiting": "Réduit le temps de mordillage à \"immédiat\"", + "options.PauseWhenIdle": "Mettre en pause en cas d'inactivité", + "options.ProbBoxLocation": "Coordonnées (haut/gauche) boîte d'information", + "options.MorePreciseProbabilities": "Calculer des probabilités plus précises", + "options.TrialOfExamine": "Nombre de calculs de probabilités ", + "options.ProtectNectarProducingFlower": "Protéger les fleurs près des ruches", + "options.RadiusCraftingFromChests": "Distance des coffres (cases) ", + "options.ScavengingRadius": "Distance des poubelles (cases) ", + "options.StaminaToEatRatio": "Seuil endurance pour l'auto-conso ", + "options.UnifyFlowerColors": "Activer ou désactiver l'uniformisation des couleurs des fleurs", + "options.ShowMousePositionWhenAssigningLocation": "Afficher la position de la souris lorsqu’il y a attribution \nde coordonnées", + "options.ButtonToggleFlowerColorUnification": "Enregistrer/effacer couleur fleur uniforme ", + "options.RadiusFarmCleanup": "Rayon en cases pour nettoyer la ferme ", + "options.CutWeeds": "Couper les mauvaises herbes (faux)", + "options.BreakRocks": "Casser les cailloux (pioche)", + "options.ChopTwigs": "Coupe des branchages (hache)", + "options.PriceBoxCoordinates": "Coordonnées (haut/gauche) fenêtre info", + "options.FishingTackleInfo": "Afficher les outils (appât et flotteurs)", + "options.TackleBoxAttach": "Attacher ensemble boîtes infos outils et probabilités poisson", + "options.TackleBoxLocation": "Coordonnées (haut/gauche) fenêtre info", + "options.ProbBoxMaxFish": "Nombre max poissons par colonne ", + "options.ThrowPower": "Ajustement force de lancer flotteur ", + "options.ThresholdStaminaPersentage": "Pourcentage de seuil de stamina pour arrêter la pêche", + "options.ToggleAFKFishing": "Activer/désactiver le mode de pêche AFK ", + "hud.afk.passedout": "La pêche a cessé en raison de votre évanouissement.", + "hud.afk.on": "La pêche AFK est activée.", + "hud.afk.off": "La pêche AFK est désactivée.", + "hud.afk.tired": "La pêche a cessé parce que vous vous sentez fatigué.", + "options.flower": "Fleur : {0}", + "options.R": "R", + "options.G": "V", + "options.B": "B", + "options.previewColor": "Couleur de prévisualisation", + "options.register": "Enregistrer", + + "flower.register": "Les couleurs de {0} seront unifiées.", + "flower.unregister": "Les couleurs de {0} ne seront plus unifiées.", + "flower.vanilla": "Vous ne pouvez pas annuler l'enregistrement des fleurs de base.", + "quality.gold": "Or", + "quality.iridium": "Iridium", + "quality.normal": "Normal", + "quality.silver": "Argent", + "stones.many": "Il y a {0} pierres sur cet étage", + "stones.none": "Il n’y a pas de pierres sur cet étage.", + "stones.one": "Il y a une pierre restante sur cet étage.", + "tab.automation": "Automatisation.", + "tab.cheats": "Triche", + "tab.controls": "Raccourci", + "tab.misc": "Divers", + "tab.UIs": "Interface utilisateur", + "taste.dislike.female": "Elle n'aime pas ce cadeau.", + "taste.dislike.male": "Il n'aime pas ce cadeau.", + "taste.gavetoday.female": "Vous lui avez déjà offert un cadeau aujourd'hui.", + "taste.gavetoday.male": "Vous lui avez déjà offert un cadeau aujourd'hui.", + "taste.gavetwogifts.female": "Vous lui avez déjà offert deux cadeaux cette semaine.", + "taste.gavetwogifts.male": "Vous lui avez déjà offert deux cadeaux cette semaine.", + "taste.hate.female": "Elle HAIT ce cadeau.", + "taste.hate.male": "Il HAIT ce cadeau.", + "taste.like.female": "Elle aime ce cadeau.", + "taste.like.male": "Il aime ce cadeau.", + "taste.love.female": "Elle ADORE ce cadeau.", + "taste.love.male": "Il ADORE ce cadeau.", + "taste.neutral.female": "Il est neutre envers ce cadeau.", + "taste.neutral.male": "Elle est neutre envers ce cadeau." +} diff --git a/JoysOfEfficiency/i18n/ja.json b/GloryOfEfficiency/i18n/ja.json similarity index 96% rename from JoysOfEfficiency/i18n/ja.json rename to GloryOfEfficiency/i18n/ja.json index a74ca53..7768a40 100644 --- a/JoysOfEfficiency/i18n/ja.json +++ b/GloryOfEfficiency/i18n/ja.json @@ -57,6 +57,10 @@ "options.FindHoeFromInventory": "クワをインベントリから探す", "options.FishingInfo": "釣りの情報を表示", "options.FishingProbabilitiesInfo": "釣りの確率を表示", + "options.FishingTackleInfo": "現在のベイトと浮きを描く", + "options.TackleBoxAttach": "タックルボックスを魚の確率ボックスに取り付ける", + "options.TackleBoxLocation": "情報ボックスの左上の座標", + "options.ProbBoxMaxFish": "列ごとの魚の数", "options.GiftInformation": "贈り物情報を表示", "options.HealthToEatRatio": "体力しきい値", "options.IdleTimeout": "一時停止までの時間", diff --git a/JoysOfEfficiency/i18n/ko.json b/GloryOfEfficiency/i18n/ko.json similarity index 95% rename from JoysOfEfficiency/i18n/ko.json rename to GloryOfEfficiency/i18n/ko.json index d02ec60..da70474 100644 --- a/JoysOfEfficiency/i18n/ko.json +++ b/GloryOfEfficiency/i18n/ko.json @@ -59,6 +59,10 @@ "options.FishInfo": "물고기 정보 상자 보기", "options.FishingInfo": "물고기 정보 상자 보기", "options.FishingProbabilitiesInfo": "낚시 확률 표시", + "options.FishingTackleInfo": "현재 미끼와 찌 그리기", + "options.TackleBoxAttach": "물고기 확률 상자에 태클 상자를 부착합니다.", + "options.TackleBoxLocation": "정보 상자의 왼쪽 상단 좌표", + "options.ProbBoxMaxFish": "열당 물고기 수", "options.GiftInformation": "선물 정보 표시 (선물할 것을 선택 후 NPC 위로 가져 가면 정보 표시)", "options.HealthToEatRatio": "자동 먹기 체력 최대치 값", "options.IdleTimeout": "게임 일시 정지를 위한 유휴 초과 시간", @@ -92,8 +96,8 @@ "hud.afk.passedout": "기절했기 때문에 낚시가 중단되었습니다.", "hud.afk.on": "AFK 낚시가 활성화되었습니다.", "hud.afk.off": "AFK 낚시가 비활성화되었습니다.", - "hud.afk.tired": "피곤해서 낚시가 중단되었습니다.", - + "hud.afk.tired": "피곤해서 낚시가 중단되었습니다.", + "options.flower": "꽃:{0}", "options.R": "R", "options.G": "G", diff --git a/JoysOfEfficiency/i18n/pt.json b/GloryOfEfficiency/i18n/pt.json similarity index 95% rename from JoysOfEfficiency/i18n/pt.json rename to GloryOfEfficiency/i18n/pt.json index e9d71f4..8eb1be4 100644 --- a/JoysOfEfficiency/i18n/pt.json +++ b/GloryOfEfficiency/i18n/pt.json @@ -52,6 +52,10 @@ "options.FishInfo": "Mostrar informação dos peixes", "options.FishingInfo": "Mostrar informação de pesca", "options.FishingProbabilitiesInfo": "Mostrar probabilidades de pesca", + "options.FishingTackleInfo": "Desenhe iscas e bobbers atuais", + "options.TackleBoxAttach": "Anexe a caixa de equipamento à caixa de probabilidades de pesca", + "options.TackleBoxLocation": "Coordenadas no canto superior esquerdo da caixa de informações", + "options.ProbBoxMaxFish": "Número de peixes por coluna", "options.GiftInformation": "Mostrar dicas de informações sobre presentes", "options.HealthToEatRatio": "Limite de saúde para comer automaticamente", "options.IdleTimeout": "Tempo limite inativo para pausar o jogo", diff --git a/JoysOfEfficiency/i18n/ru.json b/GloryOfEfficiency/i18n/ru.json similarity index 95% rename from JoysOfEfficiency/i18n/ru.json rename to GloryOfEfficiency/i18n/ru.json index de76a14..6a157c4 100644 --- a/JoysOfEfficiency/i18n/ru.json +++ b/GloryOfEfficiency/i18n/ru.json @@ -2,9 +2,9 @@ "button.awaiting": "Нажмите любую кнопку, чтобы назначить её...", "button.conflict": "Нажатая вами Кнопка уже используется", "button.esc": "Нажмите Esc для Отмены", - + "estimatedprice.title": "Примерная Стоимость", - + "fishinfo.quality": "Качество: ", "fishinfo.size": "Размер: {0}дюймов", "fishinfo.species": "Особь: {0}", @@ -12,7 +12,7 @@ "fishinfo.treasure.caught": "Сокровище поймано!", "fishinfo.treasure.incoming": "Сокровище через {0:f1}с.", "fishinfo.price": "Цена продажи:{0}G", - + "hud.paused": "Игра на паузе.", "ladder": "Лестница появилась!", @@ -20,7 +20,7 @@ "location.awaiting": "Нажмите, чтобы выбрать локацию.", "monsters.tally": "{0}: {1} убито", - + "options.AnimalHarvestRadius": "Дальность поиска животных (в тайлах)", "options.AutoAnimalDoor": "Автоматически Открывать/Закрывать Двери Животных", "options.AutoCollectCollectibles": "Автоматически собирать дикие растения поблизости", @@ -59,6 +59,10 @@ "options.FishInfo": "Показывать окошко с информацией по рыбе", "options.FishingInfo": "Показывать окошко с информацией по рыбе", "options.FishingProbabilitiesInfo": "Показывать вероятность ловли рыбы", + "options.FishingTackleInfo": "Нарисуйте текущую наживку и поплавки.", + "options.TackleBoxAttach": "Прикрепите коробку для снастей к коробке вероятности вылова рыбы.", + "options.TackleBoxLocation": "Координаты верхнего левого информационного окна", + "options.ProbBoxMaxFish": "Количество рыб в столбце", "options.GiftInformation": "Показывать Окошко с Информацией по Подаркам", "options.HealthToEatRatio": "Порог Здоровья", "options.IdleTimeout": "Длительность простоя перед паузой", @@ -89,11 +93,11 @@ "options.B": "B", "options.previewColor": "Просмотр Оттенка:", "options.register": "Учитывать", - + "flower.register": "{0} цветов будет объединяться.", "flower.unregister": "{0} цветов больше не будет объединяться.", "flower.vanilla": "Нельзя не учитывать обычные цветы.", - + "quality.gold": "Золотое", "quality.iridium": "Иридиевое", "quality.normal": "Нормальное", diff --git a/JoysOfEfficiency/i18n/zh.json b/GloryOfEfficiency/i18n/zh.json similarity index 84% rename from JoysOfEfficiency/i18n/zh.json rename to GloryOfEfficiency/i18n/zh.json index 30ae7af..425c397 100644 --- a/JoysOfEfficiency/i18n/zh.json +++ b/GloryOfEfficiency/i18n/zh.json @@ -4,21 +4,21 @@ "button.esc": "按 Esc 取消", "estimatedprice.title": "预估价格", - + "fishinfo.quality": "品质: ", "fishinfo.size": "尺寸: {0} 厘米", "fishinfo.species": "品种: {0}", - "fishinfo.treasure.appear": "宝箱出现了!", - "fishinfo.treasure.caught": "获得了宝箱!", - "fishinfo.treasure.incoming": "宝箱在 {0:f1} 秒后出现.", + "fishinfo.treasure.appear": "宝箱出现了!", + "fishinfo.treasure.caught": "获得了宝箱!", + "fishinfo.treasure.incoming": "宝箱在 {0:f1} 秒后出现。", "fishinfo.price": "出售价格:{0}G", "hud.paused": "游戏暂停", - "ladder": "梯子出现了!", + "ladder": "梯子出现了!", "location.awaiting": "单击某处以指定所需的位置。", - + "monsters.tally": "{0}:{1} 击杀", "options.AnimalHarvestRadius": "搜索动物的地图格半径", @@ -59,6 +59,10 @@ "options.FishInfo": "显示钓鱼信息", "options.FishingInfo": "显示钓鱼信息", "options.FishingProbabilitiesInfo": "显示鱼的上竿几率", + "options.FishingTackleInfo": "绘制当前的鱼饵和浮标", + "options.TackleBoxAttach": "将钓具盒连接到鱼类概率盒", + "options.TackleBoxLocation": "信息框的左上角坐标", + "options.ProbBoxMaxFish": "每列的鱼数", "options.GiftInformation": "显示礼物提示", "options.HealthToEatRatio": "自动进食阈值(生命值)", "options.IdleTimeout": "暂停游戏的空闲超时", @@ -83,16 +87,16 @@ "options.BreakRocks": "打破小石头(镐)", "options.ChopTwigs": "砍树枝(斧头)", "options.PriceBoxCoordinates": "信息框的左上角坐标", - + "options.ThrowPower": "鱼钩投掷力度", "options.ThresholdStaminaPersentage": "停止钓鱼的体力值", - "options.ToggleAFKFishing": "切换 AFK 钓鱼模式", + "options.ToggleAFKFishing": "切换 AFK 钓鱼模式", "hud.afk.passedout": "已停止钓鱼,因为你昏过去了。", "hud.afk.on": "AFK 钓鱼模式开启", "hud.afk.off": "AFK 钓鱼模式关闭", - "hud.afk.tired": "已停止钓鱼,因为你累了。", + "hud.afk.tired": "已停止钓鱼,因为你累了。", "options.flower": "花:{0}", "options.R": "R", @@ -109,26 +113,26 @@ "quality.iridium": "铱", "quality.normal": "一般", "quality.silver": "银", - "stones.many": "这个层有 {0} 块石头", - "stones.none": "这个层没剩下有石头", - "stones.one": "这个层石头只有一个", + "stones.many": "这层还有 {0} 块石头", + "stones.none": "这层没有石头", + "stones.one": "这层还有一块石头", "tab.automation": "自动化", "tab.cheats": "作弊", "tab.controls": "控制", "tab.misc": "杂项", "tab.UIs": "用户界面", - "taste.dislike.female": "她讨厌这个礼物", - "taste.dislike.male": "他讨厌这个礼物", + "taste.dislike.female": "她不喜欢这个礼物", + "taste.dislike.male": "他不喜欢这个礼物", "taste.gavetoday.female": "今天你给过她礼物了", "taste.gavetoday.male": "今天你给过他礼物了", "taste.gavetwogifts.female": "这周你给过她两次礼物了", "taste.gavetwogifts.male": "这周你给过他两次礼物了", - "taste.hate.female": "她非常讨厌这个礼物", - "taste.hate.male": "他非常讨厌这个礼物", + "taste.hate.female": "她不喜欢这个礼物", + "taste.hate.male": "他不喜欢这个礼物", "taste.like.female": "她喜欢这个礼物", "taste.like.male": "他喜欢这个礼物", - "taste.love.female": "她非常喜欢这个礼物", - "taste.love.male": "他非常喜欢这个礼物", + "taste.love.female": "她最爱这个礼物", + "taste.love.male": "他最爱这个礼物", "taste.neutral.female": "她对这份礼物持中立态度", "taste.neutral.male": "他对这份礼物持中立态度" } diff --git a/GloryOfEfficiency/manifest.json b/GloryOfEfficiency/manifest.json new file mode 100644 index 0000000..292b2c4 --- /dev/null +++ b/GloryOfEfficiency/manifest.json @@ -0,0 +1,10 @@ +{ + "Author": "hackswell", + "Description": "Adds many useful functions to make gameplay more efficient. Forked from pomepome/JoysOfEfficiency on GitHub", + "EntryDll": "GloryOfEfficiency.dll", + "MinimumApiVersion": "4.0", + "Name": "GloryOfEfficiency", + "UniqueID": "hackswell.GloryOfEfficiency", + "UpdateKeys": [ "Nexus:1234567" ], + "Version": "1.0.0" +} diff --git a/GloryOfEfficiency/packages.config b/GloryOfEfficiency/packages.config new file mode 100644 index 0000000..fb99453 --- /dev/null +++ b/GloryOfEfficiency/packages.config @@ -0,0 +1,5 @@ + + + + + diff --git a/JoysOfEfficiency/Automation/FoodAutomation.cs b/JoysOfEfficiency/Automation/FoodAutomation.cs deleted file mode 100644 index 2606f74..0000000 --- a/JoysOfEfficiency/Automation/FoodAutomation.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Linq; -using JoysOfEfficiency.Core; -using StardewValley; -using StardewValley.Tools; -using SVObject = StardewValley.Object; - -namespace JoysOfEfficiency.Automation -{ - internal class FoodAutomation - { - private static Config Config => InstanceHolder.Config; - - public static void TryToEatIfNeeded(Farmer player) - { - if (player.isEating || Game1.activeClickableMenu != null) - { - return; - } - if (player.CurrentTool != null && player.CurrentTool is FishingRod rod) - { - if (rod.inUse() && !player.UsingTool) - { - return; - } - } - - if (!(player.Stamina <= player.MaxStamina * Config.StaminaToEatRatio) && - !(player.health <= player.maxHealth * Config.HealthToEatRatio)) - { - return; - } - - SVObject itemToEat = null; - foreach (SVObject item in player.Items.OfType()) - { - if (item.Edibility <= 0) - continue; - - //It's a edible item - if (itemToEat == null || itemToEat.Edibility / itemToEat.salePrice() < item.Edibility / item.salePrice()) - { - //Found good edibility per price or just first food - itemToEat = item; - } - } - - if (itemToEat == null) - { - return; - } - - player.eatObject(itemToEat); - itemToEat.Stack--; - if (itemToEat.Stack == 0) - { - player.removeItemFromInventory(itemToEat); - } - } - } -} diff --git a/JoysOfEfficiency/Automation/MachineOperator.cs b/JoysOfEfficiency/Automation/MachineOperator.cs deleted file mode 100644 index 6c463de..0000000 --- a/JoysOfEfficiency/Automation/MachineOperator.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; -using Microsoft.Xna.Framework; -using StardewValley; -using StardewValley.Locations; -using StardewValley.Objects; -using SVObject = StardewValley.Object; -using static StardewValley.Game1; - -namespace JoysOfEfficiency.Automation -{ - internal class MachineOperator - { - public static void DepositIngredientsToMachines() - { - Farmer player = Game1.player; - if (player.CurrentItem == null || !(Game1.player.CurrentItem is SVObject item)) - { - return; - } - foreach (SVObject obj in Util.GetObjectsWithin(InstanceHolder.Config.MachineRadius).Where(IsObjectMachine)) - { - Vector2 loc = Util.GetLocationOf(currentLocation, obj); - if (obj.heldObject.Value != null) - continue; - - if (obj.Name == "Keg" && item.ParentSheetIndex == 433 && item.Stack < 5) - { - // You don't have enough beans. - return; - } - - bool flag = false; - bool accepted = obj.Name == "Furnace" ? CanFurnaceAcceptItem(item, player) : Utility.isThereAnObjectHereWhichAcceptsThisItem(currentLocation, item, (int)loc.X * tileSize, (int)loc.Y * tileSize); - if (obj is Cask) - { - if (ModEntry.IsCoGOn || ModEntry.IsCaOn) - { - if (obj.performObjectDropInAction(item, true, player)) - { - obj.heldObject.Value = null; - flag = true; - } - } - else if (currentLocation is Cellar && accepted) - { - flag = true; - } - } - else if (accepted) - { - flag = true; - } - if (!flag) - continue; - - obj.performObjectDropInAction(item, false, player); - if (!(obj.Name == "Furnace" || obj.Name == "Charcoal Kiln") || item.Stack == 0) - { - player.reduceActiveItemByOne(); - } - - return; - } - } - - public static void PullMachineResult() - { - Farmer player = Game1.player; - foreach (SVObject obj in Util.GetObjectsWithin(InstanceHolder.Config.MachineRadius).Where(IsObjectMachine)) - { - if (!obj.readyForHarvest.Value || obj.heldObject.Value == null) - continue; - - Item item = obj.heldObject.Value; - if (player.couldInventoryAcceptThisItem(item)) - obj.checkForAction(player); - } - } - - private static bool CanFurnaceAcceptItem(Item item, Farmer player) - { - if (player.getTallyOfObject(382, false) <= 0) - return false; - if (item.Stack < 5 && item.ParentSheetIndex != 80 && item.ParentSheetIndex != 82 && item.ParentSheetIndex != 330) - return false; - switch (item.ParentSheetIndex) - { - case 378: - case 380: - case 384: - case 386: - case 80: - case 82: - break; - default: - return false; - } - return true; - } - - - - - private static bool IsObjectMachine(SVObject obj) - { - if (obj is CrabPot) - return true; - - if (!obj.bigCraftable.Value) - return false; - - switch (obj.Name) - { - case "Incubator": - case "Slime Incubator": - case "Keg": - case "Preserves Jar": - case "Cheese Press": - case "Mayonnaise Machine": - case "Loom": - case "Oil Maker": - case "Seed Maker": - case "Crystalarium": - case "Recycling Machine": - case "Furnace": - case "Charcoal Kiln": - case "Slime Egg-Press": - case "Cask": - case "Bee House": - case "Mushroom Box": - case "Statue Of Endless Fortune": - case "Statue Of Perfection": - case "Tapper": - return true; - default: return false; - } - } - } -} diff --git a/JoysOfEfficiency/Automation/TrashCanScavenger.cs b/JoysOfEfficiency/Automation/TrashCanScavenger.cs deleted file mode 100644 index 57c1441..0000000 --- a/JoysOfEfficiency/Automation/TrashCanScavenger.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; -using Netcode; -using StardewModdingAPI; -using StardewValley; -using StardewValley.Locations; -using xTile.Layers; -using Object = StardewValley.Object; - -namespace JoysOfEfficiency.Automation -{ - internal class TrashCanScavenger - { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; - private static readonly Logger Logger = new Logger("TrashCanScavenger"); - - public static void ScavengeTrashCan() - { - if (!(Game1.currentLocation is Town)) - { - return; - } - - Farmer player = Game1.player; - int radius = InstanceHolder.Config.BalancedMode ? 1 : InstanceHolder.Config.ScavengingRadius; - Layer layer = Game1.currentLocation.Map.GetLayer("Buildings"); - int ox = player.getTileX(), oy = player.getTileY(); - for (int dy = -radius; dy <= radius; dy++) - { - for (int dx = -radius; dx <= radius; dx++) - { - int x = ox + dx, y = oy + dy; - - if (layer.Tiles[x, y]?.TileIndex == 78) - { - CollectTrashCan(x, y); - } - } - } - } - private static void CollectTrashCan(int x, int y) - { - if (!(Game1.currentLocation is Town town)) - { - return; - } - - NetArray garbageChecked = - Reflection.GetField>(town, "garbageChecked").GetValue(); - - string text = Game1.currentLocation.doesTileHaveProperty(x, y, "Action", "Buildings"); - int num = text != null ? Convert.ToInt32(text.Split(' ')[1]) : -1; - if (num >= 0 && num < garbageChecked.Length && !garbageChecked[num]) - { - garbageChecked[num] = true; - Game1.currentLocation.playSound("trashcan"); - Random random = new Random((int)Game1.uniqueIDForThisGame / 2 + (int)Game1.stats.DaysPlayed + 777 + num); - if (random.NextDouble() < 0.2 + Game1.player.DailyLuck) - { - int parentSheetIndex = 168; - switch (random.Next(10)) - { - case 0: - parentSheetIndex = 168; - break; - case 1: - parentSheetIndex = 167; - break; - case 2: - parentSheetIndex = 170; - break; - case 3: - parentSheetIndex = 171; - break; - case 4: - parentSheetIndex = 172; - break; - case 5: - parentSheetIndex = 216; - break; - case 6: - parentSheetIndex = Utility.getRandomItemFromSeason(Game1.currentSeason, x * 653 + y * 777, false); - break; - case 7: - parentSheetIndex = 403; - break; - case 8: - parentSheetIndex = 309 + random.Next(3); - break; - case 9: - parentSheetIndex = 153; - break; - } - switch (num) - { - case 3 when random.NextDouble() < 0.2 + Game1.player.DailyLuck: - parentSheetIndex = 535; - if (random.NextDouble() < 0.05) - { - parentSheetIndex = 749; - } - - break; - case 4 when random.NextDouble() < 0.2 + Game1.player.DailyLuck: - parentSheetIndex = 378 + random.Next(3) * 2; - break; - case 5 when random.NextDouble() < 0.2 + Game1.player.DailyLuck && Game1.dishOfTheDay != null: - parentSheetIndex = Game1.dishOfTheDay.ParentSheetIndex != 217 ? Game1.dishOfTheDay.ParentSheetIndex : 216; - break; - case 6 when random.NextDouble() < 0.2 + Game1.player.DailyLuck: - parentSheetIndex = 223; - break; - } - - Logger.Log($"You picked up trash @ [{x},{y}]"); - Game1.player.addItemByMenuIfNecessary(new Object(parentSheetIndex, 1)); - } - } - } - } -} diff --git a/JoysOfEfficiency/EventHandler/ArtifactSpotDigger.cs b/JoysOfEfficiency/EventHandler/ArtifactSpotDigger.cs deleted file mode 100644 index 505215a..0000000 --- a/JoysOfEfficiency/EventHandler/ArtifactSpotDigger.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; -using Microsoft.Xna.Framework; -using StardewValley; -using StardewValley.TerrainFeatures; -using StardewValley.Tools; - -namespace JoysOfEfficiency.EventHandler -{ - internal class ArtifactSpotDigger - { - private static Config Config => InstanceHolder.Config; - - public static void DigNearbyArtifactSpots() - { - Farmer player = Game1.player; - int radius = Config.AutoDigRadius; - Hoe hoe = Util.FindToolFromInventory(player, InstanceHolder.Config.FindHoeFromInventory); - GameLocation location = player.currentLocation; - if (hoe == null) - { - return; - } - - bool flag = false; - for (int i = -radius; i <= radius; i++) - { - for (int j = -radius; j <= radius; j++) - { - int x = player.getTileX() + i; - int y = player.getTileY() + j; - Vector2 loc = new Vector2(x, y); - if (!location.Objects.ContainsKey(loc) || location.Objects[loc].ParentSheetIndex != 590 || - location.isTileHoeDirt(loc)) - { - continue; - } - location.digUpArtifactSpot(x, y, player); - location.Objects.Remove(loc); - location.terrainFeatures.Add(loc, new HoeDirt()); - flag = true; - } - } - - if (flag) - { - Game1.playSound("hoeHit"); - } - } - - } -} diff --git a/JoysOfEfficiency/Harmony/HarmonyPatcher.cs b/JoysOfEfficiency/Harmony/HarmonyPatcher.cs deleted file mode 100644 index c5e22f2..0000000 --- a/JoysOfEfficiency/Harmony/HarmonyPatcher.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Harmony; - -namespace JoysOfEfficiency.Harmony -{ - internal class HarmonyPatcher - { - private static readonly HarmonyInstance Harmony = HarmonyInstance.Create("com.pome.joe"); - - public static void DoPatching() - { - Harmony.PatchAll(); - } - - } -} diff --git a/JoysOfEfficiency/Huds/FishingProbabilitiesBox.cs b/JoysOfEfficiency/Huds/FishingProbabilitiesBox.cs deleted file mode 100644 index c87dfd7..0000000 --- a/JoysOfEfficiency/Huds/FishingProbabilitiesBox.cs +++ /dev/null @@ -1,401 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using JoysOfEfficiency.Core; -using JoysOfEfficiency.Utils; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using StardewModdingAPI; -using StardewValley; -using StardewValley.Locations; -using StardewValley.Menus; -using StardewValley.Tools; -using xTile.Dimensions; -using Object = StardewValley.Object; -using Rectangle = Microsoft.Xna.Framework.Rectangle; - -namespace JoysOfEfficiency.Huds -{ - public class FishingProbabilitiesBox - { - private static IReflectionHelper Reflection => InstanceHolder.Reflection; - - private static readonly Logger Logger = new Logger("FishingProbabilitiesInfo"); - - private static Dictionary _fishingDictionary; - - private static bool _isFirstTimeOfFishing = true; - - public static void UpdateProbabilities(FishingRod rod) - { - if (rod.isFishing) - { - if (_isFirstTimeOfFishing) - { - - _isFirstTimeOfFishing = false; - GameLocation location = Game1.currentLocation; - - Rectangle rectangle = new Rectangle(location.fishSplashPoint.X * 64, location.fishSplashPoint.Y * 64, 64, 64); - Rectangle value = new Rectangle((int)rod.bobber.X - 80, (int)rod.bobber.Y - 80, 64, 64); - bool flag = rectangle.Intersects(value); - int clearWaterDistance = Reflection.GetField(rod, "clearWaterDistance").GetValue(); - - _fishingDictionary = GetFishes(location, rod.attachments[0]?.ParentSheetIndex ?? -1, clearWaterDistance + (flag ? 1 : 0), Game1.player, InstanceHolder.Config.MorePreciseProbabilities ? InstanceHolder.Config.TrialOfExamine : 1); - } - } - else - { - _isFirstTimeOfFishing = true; - _fishingDictionary = null; - } - } - - public static void PrintFishingInfo() - { - if (_fishingDictionary == null) - { - return; - } - DrawProbBox(_fishingDictionary); - } - - private static Dictionary GetFishes(GameLocation location, int bait, int waterDepth, Farmer who, int trial = 1) - { - List> dictList = new List>(); - for (int i = 0; i < trial; i++) - { - switch (location) - { - case Farm _: - dictList.Add(GetFishesFarm(waterDepth, who)); - break; - case MineShaft shaft: - dictList.Add(GetFishesMine(shaft, bait, waterDepth, who)); - break; - case Submarine _: - dictList.Add(GetFishesSubmarine()); - break; - default: - dictList.Add(GetFishes(waterDepth, who)); - break; - } - } - - Dictionary dict = ShuffleAndAverageFishingDictionary(dictList); - - Dictionary dict2 = - dict.OrderByDescending(x => x.Value) - .Where(kv => !IsGarbage(kv.Key)).ToDictionary(x => x.Key, x => x.Value); - double sum = dict2.Sum(kv => kv.Value); - if (1 - sum >= 0.0001) - { - dict2.Add(168, 1 - sum); - } - return dict2; - } - - private static Dictionary GetFishes(int waterDepth, Farmer who, string locationName = null) - { - Dictionary dict = new Dictionary(); - - Dictionary dictionary = Game1.content.Load>("Data\\Locations"); - string key = locationName ?? Game1.currentLocation.Name; - if (key.Equals("WitchSwamp") && !Game1.MasterPlayer.mailReceived.Contains("henchmanGone") && !Game1.player.hasItemInInventory(308, 1)) - { - return new Dictionary - { - {308,0.25} - }; - } - - try - { - if (dictionary.ContainsKey(key)) - { - string[] array = dictionary[key].Split('/')[4 + Utility.getSeasonNumber(Game1.currentSeason)].Split(' '); - Dictionary dictionary2 = new Dictionary(); - if (array.Length > 1) - { - for (int i = 0; i < array.Length; i += 2) - { - dictionary2[array[i]] = array[i + 1]; - } - } - - string[] array2 = dictionary2.Keys.ToArray(); - Dictionary dictionary3 = Game1.content.Load>("Data\\Fish"); - //Utility.Shuffle(random, array2); - foreach (string t in array2) - { - bool flag2 = true; - string[] array3 = dictionary3[Convert.ToInt32(t)].Split('/'); - string[] array4 = array3[5].Split(' '); - int num2 = Convert.ToInt32(dictionary2[t]); - if (num2 == -1 || Game1.currentLocation.getFishingLocation(who.getTileLocation()) == num2) - { - int num3 = 0; - while (num3 < array4.Length) - { - if (Game1.timeOfDay < Convert.ToInt32(array4[num3]) || - Game1.timeOfDay >= Convert.ToInt32(array4[num3 + 1])) - { - num3 += 2; - continue; - } - - flag2 = false; - break; - } - } - - if (!array3[7].Equals("both")) - { - if (array3[7].Equals("rainy") && !Game1.isRaining) - { - flag2 = true; - } - else if (array3[7].Equals("sunny") && Game1.isRaining) - { - flag2 = true; - } - } - - if (who.FishingLevel < Convert.ToInt32(array3[12])) - { - flag2 = true; - } - - if (flag2) - continue; - - double num4 = Convert.ToDouble(array3[10]); - double num5 = Convert.ToDouble(array3[11]) * num4; - num4 -= Math.Max(0, Convert.ToInt32(array3[9]) - waterDepth) * num5; - num4 += who.FishingLevel / 50f; - num4 = Math.Min(num4, 0.89999997615814209); - int num = Convert.ToInt32(t); - - dict.Add(num, num4); - } - } - } - catch (KeyNotFoundException knf) - { - Logger.Log("KeyNotFoundException occured."); - Logger.Log(knf.ToString()); - } - - return dict; - } - - private static Dictionary GetFishesSubmarine() - { - return new Dictionary - { - { 800, 0.1 }, - { 799, 0.18 }, - { 798, 0.28 }, - { 154, 0.1 }, - { 155, 0.08 }, - { 149, 0.05 }, - { 797, 0.01 } - }; - } - - private static Dictionary GetFishesMine(MineShaft shaft, int bait, int waterDepth, Farmer who) - { - Dictionary dict = new Dictionary(); - double num2 = 1.0; - num2 += 0.4 * who.FishingLevel; - num2 += waterDepth * 0.1; - double p; - int level = shaft.getMineArea(); - switch (level) - { - case 0: - case 10: - num2 += bait == 689 ? 3 : 0; - p = 0.02 + 0.01 * num2; - dict.Add(158, p); - break; - case 40: - num2 += bait == 682 ? 3 : 0; - p = 0.015 + 0.009 * num2; - dict.Add(161, p); - break; - case 80: - num2 += bait == 684 ? 3 : 0; - p = 0.01 + 0.008 * num2; - dict.Add(162, p); - break; - default: - return dict; - } - - if (level == 10 || level == 40) - { - return ConcatDictionary(dict, - MagnifyProbabilities( - GetFishes(waterDepth, who, "UndergroundMine") - .Where(kv => !IsGarbage(kv.Key)).ToDictionary(x => x.Key, x => x.Value), - 1 - p)); - } - - return dict; - } - - private static Dictionary GetFishesFarm(int waterDepth, Farmer who) - { - switch (Game1.whichFarm) - { - case 1: - return ConcatDictionary(MagnifyProbabilities(GetFishes(waterDepth, who, "Forest"), 0.3), MagnifyProbabilities(GetFishes(waterDepth, who, "Town"), 0.7)); - case 3: - return MagnifyProbabilities(GetFishes(waterDepth, who, "Forest"), 0.5); - case 2: - { - double p = 0.05 + Game1.player.DailyLuck; - return ConcatDictionary( - new Dictionary { { 734, p } }, - MagnifyProbabilities( - GetFishes(waterDepth, who, "Forest"), - (1 - p) * 0.45) - ); - } - case 4: - { - return MagnifyProbabilities( - GetFishes(waterDepth, who, "Mountain"), - 0.35); - } - default: - return GetFishes(waterDepth, who); - } - } - - private static Dictionary GetFinalProbabilities(Dictionary dict) - { - Dictionary result = new Dictionary(); - double ratio = 1.0; - foreach (KeyValuePair kv in dict) - { - result.Add(kv.Key, kv.Value * ratio); - ratio *= (1 - kv.Value); - } - - return result; - } - - private static bool IsGarbage(int index) - { - if (index >= 167 && index <= 172) - { - return true; - } - switch (index) - { - case 152: - case 153: - case 157: return true; - } - return false; - } - - private static Dictionary ShuffleAndAverageFishingDictionary(IEnumerable> list) - { - List> dicts = list.Select(dict => GetFinalProbabilities(ShuffleDictionary(dict))).ToList(); - - return AverageDictionary(dicts); - } - - private static Dictionary ShuffleDictionary(Dictionary dict) - { - KeyValuePair[] pairs = dict.ToArray(); - Utility.Shuffle(Game1.random, pairs); - return pairs.ToDictionary(x => x.Key, x => x.Value); - } - - private static Dictionary AverageDictionary(List> list) - { - Dictionary sum = new Dictionary(); - foreach (Dictionary elem in list) - { - foreach (KeyValuePair pair in elem) - { - if (sum.ContainsKey(pair.Key)) - { - sum[pair.Key] += pair.Value; - } - else - { - sum.Add(pair.Key, pair.Value); - } - } - } - - return MagnifyProbabilities(sum, 1.0 / list.Count); - } - - private static Dictionary MagnifyProbabilities(Dictionary dict, double ratio) - { - return dict.ToDictionary(kv => kv.Key, kv => kv.Value * ratio); - } - - private static Dictionary ConcatDictionary(IDictionary a, Dictionary b) - { - Dictionary dict = new Dictionary(a); - - foreach (KeyValuePair kv in b.Where(kv => !dict.ContainsKey(kv.Key))) - { - dict.Add(kv.Key, kv.Value); - } - - return dict; - } - - private static void DrawProbBox(Dictionary probabilities) - { - SpriteBatch b = Game1.spriteBatch; - Size size = GetProbBoxSize(probabilities); - IClickableMenu.drawTextureBox(Game1.spriteBatch, InstanceHolder.Config.ProbBoxCoordinates.X, InstanceHolder.Config.ProbBoxCoordinates.Y, size.Width, size.Height, Color.White); - const int square = (int)(Game1.tileSize / 1.5); - int x = InstanceHolder.Config.ProbBoxCoordinates.X + 8; - int y = InstanceHolder.Config.ProbBoxCoordinates.Y + 16; - SpriteFont font = Game1.dialogueFont; - { - foreach (KeyValuePair kv in probabilities) - { - string text = $"{kv.Value * 100:f1}%"; - Object fish = new Object(kv.Key, 1); - - fish.drawInMenu(b, new Vector2(x + 8, y), 1.0f); - Utility.drawTextWithShadow(b, text, font, new Vector2(x + 32 + square, y + 16), Color.Black); - - y += square + 16; - } - } - } - - private static Size GetProbBoxSize(Dictionary probabilities) - { - int width = 16, height = 48; - int square = (int)(Game1.tileSize / 1.5); - SpriteFont font = Game1.dialogueFont; - { - foreach (KeyValuePair kv in probabilities) - { - string text = $"{kv.Value * 100:f1}%"; - Vector2 textSize = font.MeasureString(text); - int w = square + (int)textSize.X + 64; - if (w > width) - { - width = w; - } - height += square + 16; - } - } - return new Size(width, height); - } - } -} diff --git a/JoysOfEfficiency/JoysOfEfficiency.csproj b/JoysOfEfficiency/JoysOfEfficiency.csproj deleted file mode 100644 index e41b836..0000000 --- a/JoysOfEfficiency/JoysOfEfficiency.csproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Debug - AnyCPU - {0302444C-4190-4C5D-A873-A1F80267961A} - Library - Properties - JoysOfEfficiency - JoysOfEfficiency - v4.5 - 512 - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - 7.1 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - 7.1 - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x86\Release\ - TRACE - true - pdbonly - x86 - prompt - MinimumRecommendedRules.ruleset - - - Always - - - - ..\packages\Lib.Harmony.1.2.0.1\lib\net45\0Harmony.dll - - - - - - ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Resources.resx - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/JoysOfEfficiency/manifest.json b/JoysOfEfficiency/manifest.json deleted file mode 100644 index 24cd6f6..0000000 --- a/JoysOfEfficiency/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Author": "punyo", - "Description": "Adds many useful functions to make gameplay more efficient", - "EntryDll": "JoysOfEfficiency.dll", - "MinimumApiVersion": "3.0", - "Name": "JoysOfEfficiency", - "UniqueID": "punyo.JoysOfEfficiency", - "UpdateKeys": [ "Nexus:2162" ], - "Version": "1.4.1" -} \ No newline at end of file diff --git a/JoysOfEfficiency/packages.config b/JoysOfEfficiency/packages.config deleted file mode 100644 index c138194..0000000 --- a/JoysOfEfficiency/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/LICENSE b/LICENSE index 52edd6b..ab42d4f 100644 --- a/LICENSE +++ b/LICENSE @@ -653,6 +653,7 @@ Also add information on how to contact you by electronic and paper mail. notice like this when it starts in an interactive mode: JoysOfEfficiency Copyright (C) 2018 pomepome + GloryOfEfficiency Copyright (C) 2024 Hackswell [Forked from JoysOfEfficiency above] This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -671,4 +672,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. diff --git a/global.json b/global.json new file mode 100644 index 0000000..87aef9f --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "6.0.0", + "rollForward": "latestMajor", + "allowPrerelease": false + } +} \ No newline at end of file diff --git a/testplan.txt b/testplan.txt new file mode 100644 index 0000000..a816579 --- /dev/null +++ b/testplan.txt @@ -0,0 +1,61 @@ +*** APPARENTLY WORKING *** +-------------------------- ++[Fence Gate Automation] + ++[Farm Cleaner] ++[Watering Can Refiller] ++[Harvest Automation] + +Autofill watering can + +Water nearby crops + +Harvest nearby crops + +Does NOT harvest crops on exclusion list + +Destroy dead crops + +Shake trees / fruit trees + ++[MachineOperator] + +Auto pull + +Auto push + ++[Animal Automation] + +Pet nearby animals + +Pet nearby pets + +Auto shear/milk + ++[Gift Information Tooltip] + ++Balanced Mode [every 1s for balanced, super fast otherwise] + ++[Mine HUD] + ++[Trash can Scavenger] + ++[Collectible Collector] + +Seed Spots auto digger + +Artifact auto digger + +Collect nearby collectibles + ++[Shipping Estimator] + +O[Fishing] + OFishing Probabilities Box [O Farm, +Mines, O Submarine, O Witch's Swamp, +EverywhereElse] + +Fish Info HUD + Autofisher + Auto-reeling + AFK + Treasure + +*** UNTESTED *** +---------------- + +[Idle Pause] -- UNTESTED + +[Food Automation] -- UNTESTED + Auto eat + +[Inventory Automation] -- UNTESTED + Treasure Auto-grab + +[Flower Color Unifier] -- UNTESTED + Unify Flower Colors + +[Mail Automation] -- UNTESTED