From 252207c67fd9ca003280d88e9920144715bc5f72 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Nov 2018 20:01:00 -0500 Subject: [PATCH 01/13] migrate to new NuGet package reference format --- PrismaticTools/PrismaticTools.csproj | 16 +++------------- PrismaticTools/packages.config | 4 ---- 2 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 PrismaticTools/packages.config diff --git a/PrismaticTools/PrismaticTools.csproj b/PrismaticTools/PrismaticTools.csproj index b44aab3..50fc74a 100644 --- a/PrismaticTools/PrismaticTools.csproj +++ b/PrismaticTools/PrismaticTools.csproj @@ -11,8 +11,6 @@ PrismaticTools v4.5 512 - - true @@ -53,6 +51,9 @@ + + + .\0Harmony.dll @@ -89,10 +90,6 @@ PreserveNewest - - - - @@ -112,11 +109,4 @@ - - - - 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/PrismaticTools/packages.config b/PrismaticTools/packages.config deleted file mode 100644 index d798813..0000000 --- a/PrismaticTools/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From e544fa098b346935d936f02c6ecd5d5c9ee36a80 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Nov 2018 20:01:49 -0500 Subject: [PATCH 02/13] update mod build config package --- PrismaticTools/PrismaticTools.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PrismaticTools/PrismaticTools.csproj b/PrismaticTools/PrismaticTools.csproj index 50fc74a..f4f9ed9 100644 --- a/PrismaticTools/PrismaticTools.csproj +++ b/PrismaticTools/PrismaticTools.csproj @@ -52,7 +52,7 @@ - + From 66dce3ff337d1f3e698f3bc6b2f364c49743b549 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Nov 2018 20:03:33 -0500 Subject: [PATCH 03/13] simplify project file using the new mod build config package features --- PrismaticTools/PrismaticTools.csproj | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/PrismaticTools/PrismaticTools.csproj b/PrismaticTools/PrismaticTools.csproj index f4f9ed9..30f4725 100644 --- a/PrismaticTools/PrismaticTools.csproj +++ b/PrismaticTools/PrismaticTools.csproj @@ -79,19 +79,11 @@ - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - + + + + Always @@ -104,9 +96,6 @@ Always - - PreserveNewest - \ No newline at end of file From a338e67f08bb70620aff08e7d5ec85869b9ae88e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Nov 2018 20:05:21 -0500 Subject: [PATCH 04/13] migrate to Harmony NuGet package --- PrismaticTools/0Harmony.dll | Bin 99840 -> 0 bytes PrismaticTools/PrismaticTools.csproj | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 PrismaticTools/0Harmony.dll diff --git a/PrismaticTools/0Harmony.dll b/PrismaticTools/0Harmony.dll deleted file mode 100644 index 636194290d77c8f7fbcb7979027c6b9e6d18d765..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99840 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 diff --git a/PrismaticTools/PrismaticTools.csproj b/PrismaticTools/PrismaticTools.csproj index 30f4725..fdb342c 100644 --- a/PrismaticTools/PrismaticTools.csproj +++ b/PrismaticTools/PrismaticTools.csproj @@ -52,12 +52,10 @@ + - - .\0Harmony.dll - From fa4b47eef3db18a78331195c1505eaddf7774670 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Nov 2018 20:06:16 -0500 Subject: [PATCH 05/13] bump versions for release, tweak manifest name --- PrismaticTools/manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PrismaticTools/manifest.json b/PrismaticTools/manifest.json index 02cbf0e..d4a7d7f 100644 --- a/PrismaticTools/manifest.json +++ b/PrismaticTools/manifest.json @@ -1,10 +1,10 @@ { - "Name": "PrismaticTools", + "Name": "Prismatic Tools", "Author": "stokastic", - "Version": "1.7.0", + "Version": "1.7.1", "Description": "Adds prismatic tools and sprinklers to the game.", "UniqueID": "stokastic.PrismaticTools", "EntryDll": "PrismaticTools.dll", - "MinimumApiVersion": "2.7", + "MinimumApiVersion": "2.8", "UpdateKeys": [ "Nexus:2428" ] } \ No newline at end of file From b46d9ed0f1d0430a8d9b7295b6c2fd70c20c2cf4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 26 Nov 2018 19:27:55 -0500 Subject: [PATCH 06/13] rework Harmony patching for crossplatform compatibility SMAPI automatically handles code changes between Linux/Mac and Windows, but it can't do that for type references in attributes. Using Harmony's API instead means the mod will work seamlessly across Linux/Mac/Windows without needing separate builds. --- PrismaticTools/Framework/Furnace.cs | 75 ------- PrismaticTools/Framework/PrismaticPatches.cs | 198 +++++++++++++++++++ PrismaticTools/Framework/Sprinkler.cs | 44 ----- PrismaticTools/Framework/Tools.cs | 108 ---------- PrismaticTools/ModEntry.cs | 53 ++++- PrismaticTools/PrismaticTools.csproj | 3 +- 6 files changed, 250 insertions(+), 231 deletions(-) delete mode 100644 PrismaticTools/Framework/Furnace.cs create mode 100644 PrismaticTools/Framework/PrismaticPatches.cs delete mode 100644 PrismaticTools/Framework/Tools.cs diff --git a/PrismaticTools/Framework/Furnace.cs b/PrismaticTools/Framework/Furnace.cs deleted file mode 100644 index 3f525c3..0000000 --- a/PrismaticTools/Framework/Furnace.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Harmony; -using Microsoft.Xna.Framework; -using StardewValley; - -namespace PrismaticTools.Framework { - [HarmonyPatch(typeof(Farmer), "getTallyOfObject")] - internal class PrismaticGetTallyOfObject { - static public void Postfix(ref int __result, int index, bool bigCraftable) { - if (index == 382 && !bigCraftable) { - if (__result <= 0) { - __result = 666666; - return; - } - } - } - } - - [HarmonyPatch(typeof(Object), "performObjectDropInAction")] - internal class PrismaticPerformObjectDropInAction { - - static public bool Prefix(ref Object __instance, ref bool __result, ref Item dropInItem, bool probe, Farmer who) { - if (!(dropInItem is Object)) - return false; - Object object1 = dropInItem as Object; - - if (object1.ParentSheetIndex != 74) { - return true; - } - - if (__instance.name.Equals("Furnace")) { - if (who.IsLocalPlayer && who.getTallyOfObject(382, false) == 666666) { - if (!probe && who.IsLocalPlayer) - Game1.showRedMessage(Game1.content.LoadString("Strings\\StringsFromCSFiles:Object.cs.12772")); - return false; - } - if (__instance.heldObject.Value == null && !probe) { - __instance.heldObject.Value = new Object(PrismaticBarItem.INDEX, 5, false, -1, 0); - __instance.MinutesUntilReady = 2400; - who.currentLocation.playSound("furnace"); - __instance.initializeLightSource(__instance.TileLocation, false); - __instance.showNextIndex.Value = true; - - Multiplayer multiplayer = ModEntry.ModHelper.Reflection.GetField(typeof(Game1), "multiplayer").GetValue(); - multiplayer.broadcastSprites(who.currentLocation, new TemporaryAnimatedSprite[1] { - new TemporaryAnimatedSprite(30, __instance.TileLocation * 64f + new Vector2(0.0f, -16f), Color.White, 4, false, 50f, 10, 64, (float) (((double) __instance.TileLocation.Y + 1.0) * 64.0 / 10000.0 + 9.99999974737875E-05), -1, 0) { - alphaFade = 0.005f - } - }); - for (int index = who.Items.Count - 1; index >= 0; --index) { - if (who.Items[index] is Object && (who.Items[index] as Object).ParentSheetIndex == 382) { - --who.Items[index].Stack; - if (who.Items[index].Stack <= 0) { - who.Items[index] = (Item)null; - break; - } - break; - } - } - object1.Stack -= 1; - __result = object1.Stack <= 0; - return false; - } - if (__instance.heldObject.Value == null & probe) { - if (object1.ParentSheetIndex == 74) { - __instance.heldObject.Value = new Object(); - __result = true; - return false; - } - } - } - __result = false; - return false; - } - } -} \ No newline at end of file diff --git a/PrismaticTools/Framework/PrismaticPatches.cs b/PrismaticTools/Framework/PrismaticPatches.cs new file mode 100644 index 0000000..efbee86 --- /dev/null +++ b/PrismaticTools/Framework/PrismaticPatches.cs @@ -0,0 +1,198 @@ +using Harmony; +using System.Collections.Generic; +using StardewValley; +using Microsoft.Xna.Framework; + +using StardewValley.TerrainFeatures; +using Netcode; +using StardewValley.Tools; + +namespace PrismaticTools.Framework { + internal static class PrismaticPatches { + /********* + ** Furnace patches + *********/ + public static void Farmer_GetTallyOfObject(ref int __result, int index, bool bigCraftable) { + if (index == 382 && !bigCraftable) { + if (__result <= 0) { + __result = 666666; + return; + } + } + } + + public static bool Object_PerformObjectDropInAction(ref Object __instance, ref bool __result, ref Item dropInItem, bool probe, Farmer who) { + if (!(dropInItem is Object)) + return false; + Object object1 = dropInItem as Object; + + if (object1.ParentSheetIndex != 74) { + return true; + } + + if (__instance.name.Equals("Furnace")) { + if (who.IsLocalPlayer && who.getTallyOfObject(382, false) == 666666) { + if (!probe && who.IsLocalPlayer) + Game1.showRedMessage(Game1.content.LoadString("Strings\\StringsFromCSFiles:Object.cs.12772")); + return false; + } + if (__instance.heldObject.Value == null && !probe) { + __instance.heldObject.Value = new Object(PrismaticBarItem.INDEX, 5, false, -1, 0); + __instance.MinutesUntilReady = 2400; + who.currentLocation.playSound("furnace"); + __instance.initializeLightSource(__instance.TileLocation, false); + __instance.showNextIndex.Value = true; + + Multiplayer multiplayer = ModEntry.ModHelper.Reflection.GetField(typeof(Game1), "multiplayer").GetValue(); + multiplayer.broadcastSprites(who.currentLocation, new TemporaryAnimatedSprite[1] { + new TemporaryAnimatedSprite(30, __instance.TileLocation * 64f + new Vector2(0.0f, -16f), Color.White, 4, false, 50f, 10, 64, (float) (((double) __instance.TileLocation.Y + 1.0) * 64.0 / 10000.0 + 9.99999974737875E-05), -1, 0) { + alphaFade = 0.005f + } + }); + for (int index = who.Items.Count - 1; index >= 0; --index) { + if (who.Items[index] is Object && (who.Items[index] as Object).ParentSheetIndex == 382) { + --who.Items[index].Stack; + if (who.Items[index].Stack <= 0) { + who.Items[index] = (Item)null; + break; + } + break; + } + } + object1.Stack -= 1; + __result = object1.Stack <= 0; + return false; + } + if (__instance.heldObject.Value == null & probe) { + if (object1.ParentSheetIndex == 74) { + __instance.heldObject.Value = new Object(); + __result = true; + return false; + } + } + } + __result = false; + return false; + } + + /********* + ** Sprinkler patches + *********/ + public static bool Farm_AddCrows(ref Farm __instance) { + int num1 = 0; + foreach (KeyValuePair pair in __instance.terrainFeatures.Pairs) { + if (pair.Value is HoeDirt && (pair.Value as HoeDirt).crop != null) + ++num1; + } + List vector2List = new List(); + foreach (KeyValuePair pair in __instance.objects.Pairs) { + if (pair.Value.Name.Contains("arecrow")) { + vector2List.Add(pair.Key); + } + } + int num2 = System.Math.Min(4, num1 / 16); + for (int index1 = 0; index1 < num2; ++index1) { + if (Game1.random.NextDouble() < 1.0) { + for (int index2 = 0; index2 < 10; ++index2) { + Vector2 key = __instance.terrainFeatures.Pairs.ElementAt(Game1.random.Next(__instance.terrainFeatures.Count())).Key; + if (__instance.terrainFeatures[key] is HoeDirt && (__instance.terrainFeatures[key] as HoeDirt).crop != null && ((__instance.terrainFeatures[key] as HoeDirt).crop.currentPhase.Value) > 1) { + bool flag = false; + foreach (Vector2 index3 in vector2List) { + if ((double)Vector2.Distance(index3, key) < 9.0) { + flag = true; + ++__instance.objects[index3].SpecialVariable; + break; + } + } + if (!flag) { + (__instance.terrainFeatures[key] as HoeDirt).crop = (Crop)null; + break; + } + break; + } + } + } + } + return false; + } + + /********* + ** Tool patches + *********/ + public static void Tree_PerformToolAction(ref Tree __instance, Tool t, int explosion) { + if (t is Axe axe && axe.UpgradeLevel == 5 && explosion <= 0 && ModEntry.ModHelper.Reflection.GetField(__instance, "health").GetValue() > -99f) { + __instance.health.Value = 0.0f; + } + } + + public static void FruitTree_PerformToolAction(ref FruitTree __instance, Tool t, int explosion) { + if (t is Axe axe && axe.UpgradeLevel == 5 && explosion <= 0 && ModEntry.ModHelper.Reflection.GetField(__instance, "health").GetValue() > -99f) { + __instance.health.Value = 0.0f; + } + } + + public static void Pickaxe_DoFunction(ref Pickaxe __instance, GameLocation location, int x, int y, int power, Farmer who) { + if (__instance.UpgradeLevel == 5) { + if (location.Objects.TryGetValue(new Vector2(x/64, y/64), out Object obj)) { + if (obj.Name == "Stone") { + obj.MinutesUntilReady = 0; + } + } + } + } + + public static void ResourceClump_PerformToolAction(ref ResourceClump __instance, Tool t, int damage, Vector2 tileLocation, GameLocation location) { + if (t is Axe && t.UpgradeLevel == 5 && (__instance.parentSheetIndex.Value == 600 || __instance.parentSheetIndex.Value == 602)) { + __instance.health.Value = 0; + } + } + + public static void Tool_TilesAffected_Postfix(ref List __result, Vector2 tileLocation, int power, Farmer who) { + if (power >= 6) { + __result.Clear(); + Vector2 direction; + Vector2 orth; + int radius = ModEntry.Config.PrismaticToolWidth; + int length = ModEntry.Config.PrismaticToolLength; + switch (who.FacingDirection) { + case 0: direction = new Vector2(0, -1); orth = new Vector2(1, 0); break; + case 1: direction = new Vector2(1, 0); orth = new Vector2(0, 1); break; + case 2: direction = new Vector2(0, 1); orth = new Vector2(-1, 0); break; + case 3: direction = new Vector2(-1, 0); orth = new Vector2(0, -1); break; + default: direction = new Vector2(0, 0); orth = new Vector2(0, 0); break; + } + for (int i = 0; i < length; i++) { + __result.Add(direction * i + tileLocation); + for (int j = 1; j <= radius; j++) { + __result.Add(direction * i + orth * j + tileLocation); + __result.Add(direction * i + orth * -j + tileLocation); + } + } + } + } + + public static bool Tool_Name(Tool __instance, ref string __result) { + if (__instance.UpgradeLevel == 5) { + + switch (__instance.BaseName) { + case "Axe": __result = ModEntry.ModHelper.Translation.Get("prismaticAxe"); break; + case "Pickaxe": __result = ModEntry.ModHelper.Translation.Get("prismaticPickaxe"); break; + case "Watering Can": __result = ModEntry.ModHelper.Translation.Get("prismaticWatercan"); break; + case "Hoe": __result = ModEntry.ModHelper.Translation.Get("prismaticHoe"); break; + } + //__result = "Prismatic " + __instance.BaseName; + //__result = ModEntry.ModHelper.Translation.Get("prismatic.prefix") + " " + Game1.content.LoadString("Strings\\StringsFromCSFiles:Axe.cs.1"); + return false; + } + return true; + } + + public static bool Tool_DisplayName(Tool __instance, ref string __result) { + if (__instance.UpgradeLevel == 5) { + __result = __instance.Name; + return false; + } + return true; + } + } +} diff --git a/PrismaticTools/Framework/Sprinkler.cs b/PrismaticTools/Framework/Sprinkler.cs index 3e520b0..0a4c17a 100644 --- a/PrismaticTools/Framework/Sprinkler.cs +++ b/PrismaticTools/Framework/Sprinkler.cs @@ -3,9 +3,6 @@ using StardewValley.TerrainFeatures; using StardewModdingAPI.Events; using System.Collections.Generic; -using System.Linq; -using Harmony; -using System.Reflection.Emit; namespace PrismaticTools.Framework { @@ -96,47 +93,6 @@ private static void TimeEvents_AfterDayStarted(object sender, System.EventArgs e } } } - - [HarmonyPatch(typeof(Farm), "addCrows")] - internal class PrismaticAddCrows { - static public bool Prefix(ref Farm __instance) { - int num1 = 0; - foreach (KeyValuePair pair in __instance.terrainFeatures.Pairs) { - if (pair.Value is HoeDirt && (pair.Value as HoeDirt).crop != null) - ++num1; - } - List vector2List = new List(); - foreach (KeyValuePair pair in __instance.objects.Pairs) { - if (pair.Value.Name.Contains("arecrow")) { - vector2List.Add(pair.Key); - } - } - int num2 = System.Math.Min(4, num1 / 16); - for (int index1 = 0; index1 < num2; ++index1) { - if (Game1.random.NextDouble() < 1.0) { - for (int index2 = 0; index2 < 10; ++index2) { - Vector2 key = __instance.terrainFeatures.Pairs.ElementAt(Game1.random.Next(__instance.terrainFeatures.Count())).Key; - if (__instance.terrainFeatures[key] is HoeDirt && (__instance.terrainFeatures[key] as HoeDirt).crop != null && ((__instance.terrainFeatures[key] as HoeDirt).crop.currentPhase.Value) > 1) { - bool flag = false; - foreach (Vector2 index3 in vector2List) { - if ((double)Vector2.Distance(index3, key) < 9.0) { - flag = true; - ++__instance.objects[index3].SpecialVariable; - break; - } - } - if (!flag) { - (__instance.terrainFeatures[key] as HoeDirt).crop = (Crop)null; - break; - } - break; - } - } - } - } - return false; - } - } } } diff --git a/PrismaticTools/Framework/Tools.cs b/PrismaticTools/Framework/Tools.cs deleted file mode 100644 index 2f8e3b8..0000000 --- a/PrismaticTools/Framework/Tools.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Harmony; -using System.Collections.Generic; -using StardewValley; -using Microsoft.Xna.Framework; - -using StardewValley.TerrainFeatures; -using Netcode; -using StardewValley.Tools; - -namespace PrismaticTools.Framework { - - [HarmonyPatch(typeof(Tree), "performToolAction")] - internal class PrismaticPerformToolActionTree { - static void Prefix(ref Tree __instance, Tool t, int explosion) { - if (t is Axe && (t as Axe).UpgradeLevel == 5 && explosion <= 0 && ModEntry.ModHelper.Reflection.GetField(__instance, "health").GetValue() > -99f) { - __instance.health.Value = 0.0f; - } - } - } - - [HarmonyPatch(typeof(FruitTree), "performToolAction")] - internal class PrismaticPerformToolActionFruitTree { - static void Prefix(ref FruitTree __instance, Tool t, int explosion) { - if (t is Axe && (t as Axe).UpgradeLevel == 5 && explosion <= 0 && ModEntry.ModHelper.Reflection.GetField(__instance, "health").GetValue() > -99f) { - __instance.health.Value = 0.0f; - } - } - } - - [HarmonyPatch(typeof(Pickaxe), "DoFunction")] - internal class PrimaticDoFunction { - static void Prefix(ref Pickaxe __instance, GameLocation location, int x, int y, int power, Farmer who) { - if (__instance.UpgradeLevel == 5) { - if (location.Objects.TryGetValue(new Vector2(x/64, y/64), out Object obj)) { - if (obj.Name == "Stone") { - obj.MinutesUntilReady = 0; - } - } - } - } - } - - [HarmonyPatch(typeof(ResourceClump), "performToolAction")] - internal class PrismaticPerformToolActionResourceClump { - static void Prefix(ref ResourceClump __instance, Tool t, int damage, Vector2 tileLocation, GameLocation location) { - if (t is Axe && t.UpgradeLevel == 5 && (__instance.parentSheetIndex.Value == 600 || __instance.parentSheetIndex.Value == 602)) { - __instance.health.Value = 0; - } - } - } - - [HarmonyPatch(typeof(Tool), "tilesAffected")] - internal class PrismaticTilesAffected { - static void Postfix(ref List __result, Vector2 tileLocation, int power, Farmer who) { - if (power >= 6) { - __result.Clear(); - Vector2 direction; - Vector2 orth; - int radius = ModEntry.Config.PrismaticToolWidth; - int length = ModEntry.Config.PrismaticToolLength; - switch (who.FacingDirection) { - case 0: direction = new Vector2(0, -1); orth = new Vector2(1, 0); break; - case 1: direction = new Vector2(1, 0); orth = new Vector2(0, 1); break; - case 2: direction = new Vector2(0, 1); orth = new Vector2(-1, 0); break; - case 3: direction = new Vector2(-1, 0); orth = new Vector2(0, -1); break; - default: direction = new Vector2(0, 0); orth = new Vector2(0, 0); break; - } - for (int i = 0; i < length; i++) { - __result.Add(direction * i + tileLocation); - for (int j = 1; j <= radius; j++) { - __result.Add(direction * i + orth * j + tileLocation); - __result.Add(direction * i + orth * -j + tileLocation); - } - } - } - } - } - - [HarmonyPatch(typeof(Tool), "get_Name")] - internal class PrismaticGetName { - public static bool Prefix(Tool __instance, ref string __result) { - if (__instance.UpgradeLevel == 5) { - - switch (__instance.BaseName) { - case "Axe": __result = ModEntry.ModHelper.Translation.Get("prismaticAxe"); break; - case "Pickaxe": __result = ModEntry.ModHelper.Translation.Get("prismaticPickaxe"); break; - case "Watering Can": __result = ModEntry.ModHelper.Translation.Get("prismaticWatercan"); break; - case "Hoe": __result = ModEntry.ModHelper.Translation.Get("prismaticHoe"); break; - } - //__result = "Prismatic " + __instance.BaseName; - //__result = ModEntry.ModHelper.Translation.Get("prismatic.prefix") + " " + Game1.content.LoadString("Strings\\StringsFromCSFiles:Axe.cs.1"); - return false; - } - return true; - } - } - - [HarmonyPatch(typeof(Tool), "get_DisplayName")] - internal static class CobaltDisplayNameHook { - public static bool Prefix(Tool __instance, ref string __result) { - if (__instance.UpgradeLevel == 5) { - __result = __instance.Name; - return false; - } - return true; - } - } -} diff --git a/PrismaticTools/ModEntry.cs b/PrismaticTools/ModEntry.cs index 658c927..c5c1ab0 100644 --- a/PrismaticTools/ModEntry.cs +++ b/PrismaticTools/ModEntry.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using StardewValley.Objects; using StardewValley.Locations; +using StardewValley.TerrainFeatures; using StardewValley.Tools; namespace PrismaticTools { @@ -46,7 +47,55 @@ public override void Entry(IModHelper helper) { InitColors(); var harmony = HarmonyInstance.Create("stokastic.PrismaticTools"); - harmony.PatchAll(Assembly.GetExecutingAssembly()); + this.ApplyPatches(harmony); + } + + private void ApplyPatches(HarmonyInstance harmony) { + // furnaces + harmony.Patch( + original: AccessTools.Method(typeof(Farmer), nameof(Farmer.getTallyOfObject)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Farmer_GetTallyOfObject)) + ); + harmony.Patch( + original: AccessTools.Method(typeof(Object), nameof(Object.performObjectDropInAction)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Object_PerformObjectDropInAction)) + ); + + // sprinklers + harmony.Patch( + original: AccessTools.Method(typeof(Farm), nameof(Farm.addCrows)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Farm_AddCrows)) + ); + + // tools + harmony.Patch( + original: AccessTools.Method(typeof(Tree), nameof(Tree.performToolAction)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Tree_PerformToolAction)) + ); + harmony.Patch( + original: AccessTools.Method(typeof(FruitTree), nameof(FruitTree.performToolAction)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.FruitTree_PerformToolAction)) + ); + harmony.Patch( + original: AccessTools.Method(typeof(Pickaxe), nameof(Pickaxe.DoFunction)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Pickaxe_DoFunction)) + ); + harmony.Patch( + original: AccessTools.Method(typeof(ResourceClump), nameof(ResourceClump.performToolAction)), + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.ResourceClump_PerformToolAction)) + ); + harmony.Patch( + original: AccessTools.Method(typeof(Tool), "tilesAffected"), + postfix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Tool_TilesAffected_Postfix)) + ); + harmony.Patch( + original: AccessTools.Property(typeof(Tool), nameof(Tool.Name)).GetMethod, + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Tool_Name)) + ); + harmony.Patch( + original: AccessTools.Property(typeof(Tool), nameof(Tool.DisplayName)).GetMethod, + prefix: new HarmonyMethod(typeof(PrismaticPatches), nameof(PrismaticPatches.Tool_DisplayName)) + ); } private void GameEvents_EighthUpdateTick(object sender, System.EventArgs e) { @@ -58,7 +107,7 @@ private void GameEvents_EighthUpdateTick(object sender, System.EventArgs e) { return; } - if (item == null || !(item is Object) || !((item as Object).ParentSheetIndex == PrismaticBarItem.INDEX)) { + if (!(item is Object obj) || obj.ParentSheetIndex != PrismaticBarItem.INDEX) { return; } diff --git a/PrismaticTools/PrismaticTools.csproj b/PrismaticTools/PrismaticTools.csproj index fdb342c..88181bb 100644 --- a/PrismaticTools/PrismaticTools.csproj +++ b/PrismaticTools/PrismaticTools.csproj @@ -68,11 +68,10 @@ - + - From 5abe7263b290588d306a22c81e9d79ef215509ce Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 8 Jan 2019 21:08:37 -0500 Subject: [PATCH 07/13] update for SMAPI 3.0 --- PrismaticTools/Framework/Blacksmith.cs | 12 +++++----- PrismaticTools/Framework/Sprinkler.cs | 23 +++++++++++++------ PrismaticTools/ModEntry.cs | 31 ++++++++++++++++++-------- PrismaticTools/manifest.json | 2 +- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/PrismaticTools/Framework/Blacksmith.cs b/PrismaticTools/Framework/Blacksmith.cs index 15f8656..9b788c7 100644 --- a/PrismaticTools/Framework/Blacksmith.cs +++ b/PrismaticTools/Framework/Blacksmith.cs @@ -11,15 +11,17 @@ class BlacksmithInitializer { private static int UpgradeCost = ModEntry.Config.PrismaticToolCost; private static int NumBars = 3; - public static void Init() { - MenuEvents.MenuChanged += MenuEvents_MenuChanged1; + public static void Init(IModEvents events) { + events.Display.MenuChanged += OnMenuChanged; } - private static void MenuEvents_MenuChanged1(object sender, EventArgsClickableMenuChanged e) { - if (!(e.NewMenu is ShopMenu)) { + /// Raised after a game menu is opened, closed, or replaced. + /// The event sender. + /// The event arguments. + private static void OnMenuChanged(object sender, MenuChangedEventArgs e) { + if (!(e.NewMenu is ShopMenu menu)) { return; } - ShopMenu menu = e.NewMenu as ShopMenu; List categories = ModEntry.ModHelper.Reflection.GetField>(menu, "categoriesToSellHere").GetValue(); if (!categories.Contains(Object.GemCategory) || !categories.Contains(Object.mineralsCategory) || !categories.Contains(Object.metalResources)) { return; diff --git a/PrismaticTools/Framework/Sprinkler.cs b/PrismaticTools/Framework/Sprinkler.cs index 0a4c17a..adfb172 100644 --- a/PrismaticTools/Framework/Sprinkler.cs +++ b/PrismaticTools/Framework/Sprinkler.cs @@ -12,13 +12,16 @@ namespace PrismaticTools.Framework { // - optionally makes them act as scarecrows public static class SprinklerInitializer { - public static void Init() { - TimeEvents.AfterDayStarted += TimeEvents_AfterDayStarted; - SaveEvents.AfterLoad += SaveEvents_AfterLoad; - LocationEvents.ObjectsChanged += LocationEvents_ObjectsChanged; + public static void Init(IModEvents events) { + events.GameLoop.DayStarted += OnDayStarted; + events.GameLoop.SaveLoaded += OnSaveLoaded; + events.World.ObjectListChanged += OnObjectListChanged; } - private static void SaveEvents_AfterLoad(object sender, System.EventArgs e) { + /// Raised after the player loads a save slot and the world is initialised. + /// The event sender. + /// The event arguments. + private static void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { if (ModEntry.Config.UseSprinklersAsScarecrows) { foreach (GameLocation location in Game1.locations) { foreach (Object obj in location.Objects.Values) { @@ -48,7 +51,10 @@ private static void SaveEvents_AfterLoad(object sender, System.EventArgs e) { } } - private static void LocationEvents_ObjectsChanged(object sender, EventArgsLocationObjectsChanged e) { + /// Raised after objects are added or removed in a location. + /// The event sender. + /// The event arguments. + private static void OnObjectListChanged(object sender, ObjectListChangedEventArgs e) { // adds lightsources to newly placed sprinkler if (!ModEntry.Config.UseSprinklersAsLamps) { return; @@ -64,7 +70,10 @@ private static void LocationEvents_ObjectsChanged(object sender, EventArgsLocati } } - private static void TimeEvents_AfterDayStarted(object sender, System.EventArgs e) { + /// Raised after the game begins a new day (including when the player loads a save). + /// The event sender. + /// The event arguments. + private static void OnDayStarted(object sender, DayStartedEventArgs e) { foreach (GameLocation location in Game1.locations) { foreach (Object obj in location.Objects.Values) { if (obj.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { diff --git a/PrismaticTools/ModEntry.cs b/PrismaticTools/ModEntry.cs index c5c1ab0..68a6fb1 100644 --- a/PrismaticTools/ModEntry.cs +++ b/PrismaticTools/ModEntry.cs @@ -36,13 +36,13 @@ public override void Entry(IModHelper helper) { helper.ConsoleCommands.Add("ptools", "Upgrade all tools to prismatic", UpgradeTools); - SaveEvents.AfterLoad += SaveEvents_AfterLoad; - PlayerEvents.InventoryChanged += PlayerEvents_InventoryChanged; - GameEvents.EighthUpdateTick += GameEvents_EighthUpdateTick; + helper.Events.GameLoop.SaveLoaded += OnSaveLoaded; + helper.Events.GameLoop.UpdateTicked += OnUpdateTicked; + helper.Events.Player.InventoryChanged += OnInventoryChanged; helper.Content.AssetEditors.Add(new AssetEditor()); - SprinklerInitializer.Init(); - BlacksmithInitializer.Init(); + SprinklerInitializer.Init(helper.Events); + BlacksmithInitializer.Init(helper.Events); InitColors(); @@ -98,7 +98,13 @@ private void ApplyPatches(HarmonyInstance harmony) { ); } - private void GameEvents_EighthUpdateTick(object sender, System.EventArgs e) { + /// Raised after the game state is updated (≈60 times per second). + /// The event sender. + /// The event arguments. + private void OnUpdateTicked(object sender, UpdateTickedEventArgs e) { + if (!e.IsMultipleOf(8)) + return; + Farmer farmer = Game1.player; Item item; try { @@ -147,11 +153,18 @@ private void AddLightsToInventoryItems() { } } - private void PlayerEvents_InventoryChanged(object sender, EventArgsInventoryChanged e) { - AddLightsToInventoryItems(); + /// Raised after items are added or removed to a player's inventory. + /// The event sender. + /// The event arguments. + private void OnInventoryChanged(object sender, InventoryChangedEventArgs e) { + if (e.IsLocalPlayer) + AddLightsToInventoryItems(); } - private void SaveEvents_AfterLoad(object sender, System.EventArgs e) { + /// Raised after the player loads a save slot and the world is initialised. + /// The event sender. + /// The event arguments. + private void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { // force add sprinkler recipe for people who were level 10 before installing mod if (Game1.player.FarmingLevel >= PrismaticSprinklerItem.CRAFTING_LEVEL) { try { diff --git a/PrismaticTools/manifest.json b/PrismaticTools/manifest.json index d4a7d7f..754d047 100644 --- a/PrismaticTools/manifest.json +++ b/PrismaticTools/manifest.json @@ -5,6 +5,6 @@ "Description": "Adds prismatic tools and sprinklers to the game.", "UniqueID": "stokastic.PrismaticTools", "EntryDll": "PrismaticTools.dll", - "MinimumApiVersion": "2.8", + "MinimumApiVersion": "2.10.1", "UpdateKeys": [ "Nexus:2428" ] } \ No newline at end of file From 3ece888fb738d46dfa4dc8acacc04ff9fc750186 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 8 Jan 2019 21:09:40 -0500 Subject: [PATCH 08/13] update for Stardew Valley 1.3.33 --- PrismaticTools/Framework/Sprinkler.cs | 30 +++++++++++++-------------- PrismaticTools/ModEntry.cs | 7 +++---- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/PrismaticTools/Framework/Sprinkler.cs b/PrismaticTools/Framework/Sprinkler.cs index adfb172..f1e348b 100644 --- a/PrismaticTools/Framework/Sprinkler.cs +++ b/PrismaticTools/Framework/Sprinkler.cs @@ -1,8 +1,10 @@ -using Microsoft.Xna.Framework; +using System; +using Microsoft.Xna.Framework; using StardewValley; using StardewValley.TerrainFeatures; using StardewModdingAPI.Events; using System.Collections.Generic; +using SObject = StardewValley.Object; namespace PrismaticTools.Framework { @@ -24,7 +26,7 @@ public static void Init(IModEvents events) { private static void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { if (ModEntry.Config.UseSprinklersAsScarecrows) { foreach (GameLocation location in Game1.locations) { - foreach (Object obj in location.Objects.Values) { + foreach (SObject obj in location.Objects.Values) { if (obj.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { obj.Name = "Prismatic Scarecrow Sprinkler"; } @@ -36,16 +38,14 @@ private static void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { if (!ModEntry.Config.UseSprinklersAsLamps) { return; } - Object sprinkler; + foreach (GameLocation location in Game1.locations) { - if (location is GameLocation) { - foreach (KeyValuePair pair in location.objects.Pairs) { - if (location.objects[pair.Key].ParentSheetIndex == PrismaticSprinklerItem.INDEX) { - sprinkler = location.objects[pair.Key]; - int id = (int)sprinkler.TileLocation.X * 4000 + (int)sprinkler.TileLocation.Y; - sprinkler.lightSource = new LightSource(4, new Vector2((sprinkler.boundingBox.X + 32), (sprinkler.boundingBox.Y + 32)), 2.0f, Color.Black, id); - location.sharedLights.Add(sprinkler.lightSource.Clone()); - } + foreach (KeyValuePair pair in location.objects.Pairs) { + if (location.objects[pair.Key].ParentSheetIndex == PrismaticSprinklerItem.INDEX) { + SObject sprinkler = location.objects[pair.Key]; + int id = (int)sprinkler.TileLocation.X * 4000 + (int)sprinkler.TileLocation.Y; + sprinkler.lightSource = new LightSource(4, new Vector2((sprinkler.boundingBox.X + 32), (sprinkler.boundingBox.Y + 32)), 2.0f, Color.Black, id); + location.sharedLights.Add(id, sprinkler.lightSource.Clone()); } } } @@ -59,13 +59,13 @@ private static void OnObjectListChanged(object sender, ObjectListChangedEventArg if (!ModEntry.Config.UseSprinklersAsLamps) { return; } - foreach (KeyValuePair pair in e.Added) { - Object obj = pair.Value; + foreach (KeyValuePair pair in e.Added) { + SObject obj = pair.Value; if (obj.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { int id = (int)obj.TileLocation.X * 4000 + (int)obj.TileLocation.Y; obj.lightSource = new LightSource(4, new Vector2((obj.boundingBox.X + 32), (obj.boundingBox.Y + 32)), 2.0f, Color.Black, id); obj.Name = "Prismatic Scarecrow Sprinkler"; - Game1.currentLocation.sharedLights.Add(obj.lightSource.Clone()); + e.Location.sharedLights.Add(id, obj.lightSource.Clone()); } } } @@ -75,7 +75,7 @@ private static void OnObjectListChanged(object sender, ObjectListChangedEventArg /// The event arguments. private static void OnDayStarted(object sender, DayStartedEventArgs e) { foreach (GameLocation location in Game1.locations) { - foreach (Object obj in location.Objects.Values) { + foreach (SObject obj in location.Objects.Values) { if (obj.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { // add water spray animation diff --git a/PrismaticTools/ModEntry.cs b/PrismaticTools/ModEntry.cs index 68a6fb1..90e3c74 100644 --- a/PrismaticTools/ModEntry.cs +++ b/PrismaticTools/ModEntry.cs @@ -1,6 +1,5 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using System.Reflection; using Harmony; using StardewValley; @@ -117,9 +116,9 @@ private void OnUpdateTicked(object sender, UpdateTickedEventArgs e) { return; } - for (int i=0; i Date: Wed, 9 Jan 2019 19:12:28 -0500 Subject: [PATCH 09/13] fix sprinkler light feature --- PrismaticTools/Framework/Sprinkler.cs | 55 ++++++++++++++------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/PrismaticTools/Framework/Sprinkler.cs b/PrismaticTools/Framework/Sprinkler.cs index f1e348b..b0f1b42 100644 --- a/PrismaticTools/Framework/Sprinkler.cs +++ b/PrismaticTools/Framework/Sprinkler.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using StardewValley; using StardewValley.TerrainFeatures; using StardewModdingAPI.Events; @@ -34,19 +33,11 @@ private static void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { } } - // set light source - if (!ModEntry.Config.UseSprinklersAsLamps) { - return; - } - - foreach (GameLocation location in Game1.locations) { - foreach (KeyValuePair pair in location.objects.Pairs) { - if (location.objects[pair.Key].ParentSheetIndex == PrismaticSprinklerItem.INDEX) { - SObject sprinkler = location.objects[pair.Key]; - int id = (int)sprinkler.TileLocation.X * 4000 + (int)sprinkler.TileLocation.Y; - sprinkler.lightSource = new LightSource(4, new Vector2((sprinkler.boundingBox.X + 32), (sprinkler.boundingBox.Y + 32)), 2.0f, Color.Black, id); - location.sharedLights.Add(id, sprinkler.lightSource.Clone()); - } + // set light sources + if (ModEntry.Config.UseSprinklersAsLamps) { + foreach (GameLocation location in Game1.locations) { + foreach (KeyValuePair pair in location.objects.Pairs) + TryEnablePrismaticSprinkler(location, pair.Key, pair.Value); } } } @@ -55,21 +46,31 @@ private static void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { /// The event sender. /// The event arguments. private static void OnObjectListChanged(object sender, ObjectListChangedEventArgs e) { - // adds lightsources to newly placed sprinkler - if (!ModEntry.Config.UseSprinklersAsLamps) { - return; - } - foreach (KeyValuePair pair in e.Added) { - SObject obj = pair.Value; - if (obj.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { - int id = (int)obj.TileLocation.X * 4000 + (int)obj.TileLocation.Y; - obj.lightSource = new LightSource(4, new Vector2((obj.boundingBox.X + 32), (obj.boundingBox.Y + 32)), 2.0f, Color.Black, id); - obj.Name = "Prismatic Scarecrow Sprinkler"; - e.Location.sharedLights.Add(id, obj.lightSource.Clone()); - } + // adds light sources to newly placed sprinklers + if (ModEntry.Config.UseSprinklersAsLamps) { + foreach (KeyValuePair pair in e.Added) + TryEnablePrismaticSprinkler(e.Location, pair.Key, pair.Value); } } + /// Try to add the light source for a prismatic sprinkler, if applicable. + /// The location containing the sprinkler. + /// The sprinkler's tile coordinate within the location. + /// The object to check. + private static void TryEnablePrismaticSprinkler(GameLocation location, Vector2 tile, SObject obj) + { + if (obj.ParentSheetIndex != PrismaticSprinklerItem.INDEX || !ModEntry.Config.UseSprinklersAsLamps) + return; + + // set name + obj.Name = "Prismatic Scarecrow Sprinkler"; + + // add light source + int id = (int)tile.X * 4000 + (int)tile.Y; + obj.lightSource = new LightSource(4, tile * Game1.tileSize, 2.0f, Color.Black, id); + location.sharedLights.Add(id, obj.lightSource); + } + /// Raised after the game begins a new day (including when the player loads a save). /// The event sender. /// The event arguments. From 47d15a3a2405335e5407d66785f7b6dfb066aff3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 18 Jan 2019 22:11:59 -0500 Subject: [PATCH 10/13] fix null reference exceptions in some cases --- PrismaticTools/ModEntry.cs | 65 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/PrismaticTools/ModEntry.cs b/PrismaticTools/ModEntry.cs index 90e3c74..b580015 100644 --- a/PrismaticTools/ModEntry.cs +++ b/PrismaticTools/ModEntry.cs @@ -179,39 +179,45 @@ private void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { private void IndexCompatibilityFix() { var watch = System.Diagnostics.Stopwatch.StartNew(); foreach (GameLocation location in Game1.locations) { - if (location is FarmHouse) { - // check fridge - if ((location as FarmHouse).fridge.Value != null) { - foreach (Item item in (location as FarmHouse).fridge.Value.items) { - if (item == null) { - continue; - } - if (item.Name.Contains("Prismatic")) { + // check fridge + if (location is FarmHouse farmhouse && farmhouse.fridge.Value is Chest fridge) { + foreach (Item item in fridge.items) { + if (item?.Name != null && item.Name.Contains("Prismatic")) { SwapIndex(item); } } - } } - foreach (Object obj in location.Objects.Values) { - // check chests, signposts, furnaces, and placed sprinklers - if (obj == null) { - continue; - } - if (obj is Chest) { - foreach (Item item in (obj as Chest).items) { - if (item.Name.Contains("Prismatic")) { - SwapIndex(item); + // check chests, signposts, furnaces, and placed sprinklers + foreach (Object obj in location.Objects.Values) + { + switch (obj) + { + // chest + case Chest chest: + foreach (Item item in chest.items) { + if (item?.Name != null && item.Name.Contains("Prismatic")) { + SwapIndex(item); + } } - } - } else if (obj is Sign) { - SwapIndex((obj as Sign).displayItem.Value); - } else if (obj.bigCraftable.Value && obj.name.Equals("Furnace")) { - if (obj.heldObject.Value != null) { - SwapIndex((obj.heldObject.Value)); - } - } else if (obj.ParentSheetIndex == PrismaticBarItem.OLD_INDEX || obj.ParentSheetIndex == PrismaticSprinklerItem.OLD_INDEX) { - SwapIndex(obj); + break; + + // sign + case Sign sign: + SwapIndex(sign.displayItem.Value); + break; + + default: + // furnace + if (obj.bigCraftable.Value && obj.Name == "Furnace") { + SwapIndex(obj.heldObject.Value); + } + + // prismatic bar/sprinkler + else if (obj.ParentSheetIndex == PrismaticBarItem.OLD_INDEX || obj.ParentSheetIndex == PrismaticSprinklerItem.OLD_INDEX) { + SwapIndex(obj); + } + break; } } } @@ -221,11 +227,16 @@ private void IndexCompatibilityFix() { SwapIndex(item); } } + watch.Stop(); Monitor.Log($"IndexCompatibility exec time: {watch.ElapsedMilliseconds} ms", LogLevel.Trace); } private void SwapIndex(Item item) { + if (item == null) { + return; + } + if (item.ParentSheetIndex == PrismaticBarItem.OLD_INDEX) { item.ParentSheetIndex = PrismaticBarItem.INDEX; } From 9ed0fe64651c032cc9279fe64550db5963f0c7cb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 18 Jan 2019 22:12:43 -0500 Subject: [PATCH 11/13] fix 'key has already been added' error in some cases --- PrismaticTools/Framework/Sprinkler.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/PrismaticTools/Framework/Sprinkler.cs b/PrismaticTools/Framework/Sprinkler.cs index b0f1b42..00238b8 100644 --- a/PrismaticTools/Framework/Sprinkler.cs +++ b/PrismaticTools/Framework/Sprinkler.cs @@ -67,8 +67,11 @@ private static void TryEnablePrismaticSprinkler(GameLocation location, Vector2 t // add light source int id = (int)tile.X * 4000 + (int)tile.Y; - obj.lightSource = new LightSource(4, tile * Game1.tileSize, 2.0f, Color.Black, id); - location.sharedLights.Add(id, obj.lightSource); + if (!location.sharedLights.ContainsKey(id)) + { + obj.lightSource = new LightSource(4, tile * Game1.tileSize, 2.0f, Color.Black, id); + location.sharedLights.Add(id, obj.lightSource); + } } /// Raised after the game begins a new day (including when the player loads a save). From 5fb070aaadef248ec6de8bcdf05ad17f6c05b0cf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 25 May 2019 12:09:58 -0400 Subject: [PATCH 12/13] remove old migration --- PrismaticTools/Framework/PrismaticItems.cs | 2 - PrismaticTools/ModEntry.cs | 71 ---------------------- 2 files changed, 73 deletions(-) diff --git a/PrismaticTools/Framework/PrismaticItems.cs b/PrismaticTools/Framework/PrismaticItems.cs index cec1db7..9b1331d 100644 --- a/PrismaticTools/Framework/PrismaticItems.cs +++ b/PrismaticTools/Framework/PrismaticItems.cs @@ -4,7 +4,6 @@ namespace PrismaticTools.Framework { public class PrismaticSprinklerItem { public const int INDEX = 1113; - public const int OLD_INDEX = 813; public const string NAME = "Prismatic Sprinkler"; public const int PRICE = 2000; public const int EDIBILITY = -300; @@ -16,7 +15,6 @@ public class PrismaticSprinklerItem { public class PrismaticBarItem : Object { public const int INDEX = 1112; - public const int OLD_INDEX = 812; public const string NAME = "Prismatic Bar"; public const string DESCRIPTION = "A mystical ingot forged from legend itself."; public const int PRICE = 2500; diff --git a/PrismaticTools/ModEntry.cs b/PrismaticTools/ModEntry.cs index b580015..1b492f8 100644 --- a/PrismaticTools/ModEntry.cs +++ b/PrismaticTools/ModEntry.cs @@ -171,80 +171,9 @@ private void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { } catch { } } - IndexCompatibilityFix(); AddLightsToInventoryItems(); } - // used to resolve asset conflicts with other mods - private void IndexCompatibilityFix() { - var watch = System.Diagnostics.Stopwatch.StartNew(); - foreach (GameLocation location in Game1.locations) { - // check fridge - if (location is FarmHouse farmhouse && farmhouse.fridge.Value is Chest fridge) { - foreach (Item item in fridge.items) { - if (item?.Name != null && item.Name.Contains("Prismatic")) { - SwapIndex(item); - } - } - } - - // check chests, signposts, furnaces, and placed sprinklers - foreach (Object obj in location.Objects.Values) - { - switch (obj) - { - // chest - case Chest chest: - foreach (Item item in chest.items) { - if (item?.Name != null && item.Name.Contains("Prismatic")) { - SwapIndex(item); - } - } - break; - - // sign - case Sign sign: - SwapIndex(sign.displayItem.Value); - break; - - default: - // furnace - if (obj.bigCraftable.Value && obj.Name == "Furnace") { - SwapIndex(obj.heldObject.Value); - } - - // prismatic bar/sprinkler - else if (obj.ParentSheetIndex == PrismaticBarItem.OLD_INDEX || obj.ParentSheetIndex == PrismaticSprinklerItem.OLD_INDEX) { - SwapIndex(obj); - } - break; - } - } - } - - foreach (Item item in Game1.player.Items) { - if (item != null && item.Name.Contains("Prismatic")) { - SwapIndex(item); - } - } - - watch.Stop(); - Monitor.Log($"IndexCompatibility exec time: {watch.ElapsedMilliseconds} ms", LogLevel.Trace); - } - - private void SwapIndex(Item item) { - if (item == null) { - return; - } - - if (item.ParentSheetIndex == PrismaticBarItem.OLD_INDEX) { - item.ParentSheetIndex = PrismaticBarItem.INDEX; - } - if (item.ParentSheetIndex == PrismaticSprinklerItem.OLD_INDEX) { - item.ParentSheetIndex = PrismaticSprinklerItem.INDEX; - } - } - private void InitColors() { int n = 24; for(int i=0; i Date: Sat, 25 May 2019 12:34:51 -0400 Subject: [PATCH 13/13] add editorconfig to keep formatting consistent, minor code formatting --- .editorconfig | 72 +++++++++++++++ PrismaticTools.sln | 12 ++- PrismaticTools.sln.DotSettings | 3 + PrismaticTools/Framework/AssetEditor.cs | 31 ++++--- PrismaticTools/Framework/Blacksmith.cs | 17 ++-- PrismaticTools/Framework/PrismaticAPI.cs | 7 +- PrismaticTools/Framework/PrismaticItems.cs | 5 +- PrismaticTools/Framework/PrismaticPatches.cs | 14 ++- PrismaticTools/Framework/Sprinkler.cs | 15 ++-- PrismaticTools/ModConfig.cs | 22 ++--- PrismaticTools/ModEntry.cs | 92 +++++++++----------- PrismaticTools/i18n/de.json | 22 ++--- PrismaticTools/i18n/default.json | 22 ++--- PrismaticTools/i18n/zh.json | 22 ++--- PrismaticTools/manifest.json | 20 ++--- 15 files changed, 215 insertions(+), 161 deletions(-) create mode 100644 .editorconfig create mode 100644 PrismaticTools.sln.DotSettings diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..083f401 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,72 @@ +# topmost editorconfig +root: true + +########## +## General formatting +## documentation: http://editorconfig.org +########## +[*] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +[*.{csproj,nuspec,targets}] +indent_size = 2 + +[*.csproj] +insert_final_newline = false + +########## +## C# formatting +## documentation: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference +########## +[*.cs] + +#sort 'system' usings first +dotnet_sort_system_directives_first = true + +# use 'this.' qualifier +dotnet_style_qualification_for_field = true:error +dotnet_style_qualification_for_property = true:error +dotnet_style_qualification_for_method = true:error +dotnet_style_qualification_for_event = true:error + +# use language keywords (like int) instead of type (like Int32) +dotnet_style_predefined_type_for_locals_parameters_members = true:error +dotnet_style_predefined_type_for_member_access = true:error + +# don't use 'var' for language keywords +csharp_style_var_for_built_in_types = false:error + +# suggest modern C# features where simpler +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion + +# prefer method block bodies +csharp_style_expression_bodied_methods = false:suggestion +csharp_style_expression_bodied_constructors = false:suggestion + +# prefer property expression bodies +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_expression_bodied_indexers = true:suggestion +csharp_style_expression_bodied_accessors = true:suggestion + +# prefer inline out variables +csharp_style_inlined_variable_declaration = true:warning + +# avoid superfluous braces +csharp_prefer_braces = false:suggestion + +# set block newline conventions +csharp_new_line_before_open_brace = true +csharp_new_line_before_else = false +csharp_new_line_before_catch = false diff --git a/PrismaticTools.sln b/PrismaticTools.sln index 40856f6..45fa01d 100644 --- a/PrismaticTools.sln +++ b/PrismaticTools.sln @@ -1,10 +1,18 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27703.2026 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrismaticTools", "PrismaticTools\PrismaticTools.csproj", "{C24166EE-9341-4760-86B3-F89B326F3FC0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{7EF5E22B-2A2D-4B4A-9903-6B118B874F64}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + LICENSE = LICENSE + README.md = README.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/PrismaticTools.sln.DotSettings b/PrismaticTools.sln.DotSettings new file mode 100644 index 0000000..7cc51a4 --- /dev/null +++ b/PrismaticTools.sln.DotSettings @@ -0,0 +1,3 @@ + + DO_NOT_SHOW + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> \ No newline at end of file diff --git a/PrismaticTools/Framework/AssetEditor.cs b/PrismaticTools/Framework/AssetEditor.cs index 79611c5..086d010 100644 --- a/PrismaticTools/Framework/AssetEditor.cs +++ b/PrismaticTools/Framework/AssetEditor.cs @@ -1,16 +1,15 @@ -using Microsoft.Xna.Framework; +using System.Collections.Generic; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI; using StardewValley; -using System.Collections.Generic; namespace PrismaticTools.Framework { public class AssetEditor : IAssetEditor { - - private string barName = ModEntry.ModHelper.Translation.Get("prismaticBar.name"); - private string barDesc = ModEntry.ModHelper.Translation.Get("prismaticBar.description"); - private string sprinklerName = ModEntry.ModHelper.Translation.Get("prismaticSprinkler.name"); - private string sprinklerDesc = ModEntry.ModHelper.Translation.Get("prismaticSprinkler.description"); + private readonly string barName = ModEntry.ModHelper.Translation.Get("prismaticBar.name"); + private readonly string barDesc = ModEntry.ModHelper.Translation.Get("prismaticBar.description"); + private readonly string sprinklerName = ModEntry.ModHelper.Translation.Get("prismaticSprinkler.name"); + private readonly string sprinklerDesc = ModEntry.ModHelper.Translation.Get("prismaticSprinkler.description"); public bool CanEdit(IAssetInfo asset) { bool canEdit = @@ -24,16 +23,16 @@ public bool CanEdit(IAssetInfo asset) { public void Edit(IAssetData asset) { if (asset.AssetNameEquals("Maps/springobjects")) { - Texture2D bar = ModEntry.ModHelper.Content.Load("Assets/prismaticBar.png", ContentSource.ModFolder); - Texture2D sprinkler = ModEntry.ModHelper.Content.Load("Assets/prismaticSprinkler.png", ContentSource.ModFolder); + Texture2D bar = ModEntry.ModHelper.Content.Load("Assets/prismaticBar.png"); + Texture2D sprinkler = ModEntry.ModHelper.Content.Load("Assets/prismaticSprinkler.png"); Texture2D old = asset.AsImage().Data; asset.ReplaceWith(new Texture2D(Game1.graphics.GraphicsDevice, old.Width, System.Math.Max(old.Height, 1200 / 24 * 16))); asset.AsImage().PatchImage(old); - asset.AsImage().PatchImage(bar, targetArea: Rektangle(PrismaticBarItem.INDEX)); - asset.AsImage().PatchImage(sprinkler, targetArea: Rektangle(PrismaticSprinklerItem.INDEX)); + asset.AsImage().PatchImage(bar, targetArea: this.GetRectangle(PrismaticBarItem.INDEX)); + asset.AsImage().PatchImage(sprinkler, targetArea: this.GetRectangle(PrismaticSprinklerItem.INDEX)); } else if (asset.AssetNameEquals("Data/ObjectInformation")) { - asset.AsDictionary().Data.Add(PrismaticBarItem.INDEX, $"{barName}/{PrismaticBarItem.PRICE}/{PrismaticBarItem.EDIBILITY}/{PrismaticBarItem.TYPE} {PrismaticBarItem.CATEGORY}/{barName}/{barDesc}"); - asset.AsDictionary().Data.Add(PrismaticSprinklerItem.INDEX, $"{sprinklerName}/{PrismaticSprinklerItem.PRICE}/{PrismaticSprinklerItem.EDIBILITY}/{PrismaticSprinklerItem.TYPE} {PrismaticSprinklerItem.CATEGORY}/{sprinklerName}/{sprinklerDesc}"); + asset.AsDictionary().Data.Add(PrismaticBarItem.INDEX, $"{this.barName}/{PrismaticBarItem.PRICE}/{PrismaticBarItem.EDIBILITY}/{PrismaticBarItem.TYPE} {PrismaticBarItem.CATEGORY}/{this.barName}/{this.barDesc}"); + asset.AsDictionary().Data.Add(PrismaticSprinklerItem.INDEX, $"{this.sprinklerName}/{PrismaticSprinklerItem.PRICE}/{PrismaticSprinklerItem.EDIBILITY}/{PrismaticSprinklerItem.TYPE} {PrismaticSprinklerItem.CATEGORY}/{this.sprinklerName}/{this.sprinklerDesc}"); } else if (asset.AssetNameEquals("Data/CraftingRecipes")) { IAssetDataForDictionary oldDict = asset.AsDictionary(); Dictionary newDict = new Dictionary(); @@ -42,7 +41,7 @@ public void Edit(IAssetData asset) { newDict.Add(key, oldDict.Data[key]); if (key.Equals("Iridium Sprinkler")) { if (asset.Locale != "en") - newDict.Add("Prismatic Sprinkler", $"{PrismaticBarItem.INDEX} 2 787 2/Home/{PrismaticSprinklerItem.INDEX}/false/Farming {PrismaticSprinklerItem.CRAFTING_LEVEL}/{sprinklerName}"); + newDict.Add("Prismatic Sprinkler", $"{PrismaticBarItem.INDEX} 2 787 2/Home/{PrismaticSprinklerItem.INDEX}/false/Farming {PrismaticSprinklerItem.CRAFTING_LEVEL}/{this.sprinklerName}"); else newDict.Add("Prismatic Sprinkler", $"{PrismaticBarItem.INDEX} 2 787 2/Home/{PrismaticSprinklerItem.INDEX}/false/Farming {PrismaticSprinklerItem.CRAFTING_LEVEL}"); } @@ -52,12 +51,12 @@ public void Edit(IAssetData asset) { asset.AsDictionary().Data.Add(key, newDict[key]); } } else if (asset.AssetNameEquals("TileSheets\\tools")) { - asset.AsImage().PatchImage(ModEntry.toolsTexture, null, null, PatchMode.Overlay); + asset.AsImage().PatchImage(ModEntry.ToolsTexture, null, null, PatchMode.Overlay); } } - public Rectangle Rektangle(int id) { + public Rectangle GetRectangle(int id) { int x = (id % 24) * 16; int y = (id / 24) * 16; return new Rectangle(x, y, 16, 16); diff --git a/PrismaticTools/Framework/Blacksmith.cs b/PrismaticTools/Framework/Blacksmith.cs index 9b788c7..55a7cf5 100644 --- a/PrismaticTools/Framework/Blacksmith.cs +++ b/PrismaticTools/Framework/Blacksmith.cs @@ -1,15 +1,12 @@ -using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; using StardewModdingAPI.Events; using StardewValley; using StardewValley.Menus; using StardewValley.Tools; -using System.Collections.Generic; namespace PrismaticTools.Framework { - class BlacksmithInitializer { - - private static int UpgradeCost = ModEntry.Config.PrismaticToolCost; - private static int NumBars = 3; + internal class BlacksmithInitializer { + private static readonly int UpgradeCost = ModEntry.Config.PrismaticToolCost; public static void Init(IModEvents events) { events.Display.MenuChanged += OnMenuChanged; @@ -40,22 +37,22 @@ private static void OnMenuChanged(object sender, MenuChangedEventArgs e) { if (toolFromName1 != null && toolFromName1.UpgradeLevel == 4) { tool = new Axe { UpgradeLevel = 5 }; forSale.Add(tool); - stock.Add(tool, new int[3] { UpgradeCost, 1, PrismaticBarItem.INDEX }); + stock.Add(tool, new[] { UpgradeCost, 1, PrismaticBarItem.INDEX }); } if (toolFromName2 != null && toolFromName2.UpgradeLevel == 4) { tool = new WateringCan { UpgradeLevel = 5 }; forSale.Add(tool); - stock.Add(tool, new int[3] { UpgradeCost, 1, PrismaticBarItem.INDEX }); + stock.Add(tool, new[] { UpgradeCost, 1, PrismaticBarItem.INDEX }); } if (toolFromName3 != null && toolFromName3.UpgradeLevel == 4) { tool = new Pickaxe { UpgradeLevel = 5 }; forSale.Add(tool); - stock.Add(tool, new int[3] { UpgradeCost, 1, PrismaticBarItem.INDEX }); + stock.Add(tool, new[] { UpgradeCost, 1, PrismaticBarItem.INDEX }); } if (toolFromName4 != null && toolFromName4.UpgradeLevel == 4) { tool = new Hoe { UpgradeLevel = 5 }; forSale.Add(tool); - stock.Add(tool, new int[3] { UpgradeCost, 1, PrismaticBarItem.INDEX }); + stock.Add(tool, new[] { UpgradeCost, 1, PrismaticBarItem.INDEX }); } } } diff --git a/PrismaticTools/Framework/PrismaticAPI.cs b/PrismaticTools/Framework/PrismaticAPI.cs index 83e2a37..dc4abcc 100644 --- a/PrismaticTools/Framework/PrismaticAPI.cs +++ b/PrismaticTools/Framework/PrismaticAPI.cs @@ -1,5 +1,5 @@ -using Microsoft.Xna.Framework; using System.Collections.Generic; +using Microsoft.Xna.Framework; namespace PrismaticTools.Framework { public class PrismaticAPI { @@ -9,10 +9,9 @@ public class PrismaticAPI { public bool ArePrismaticSprinklersScarecrows { get; } = ModEntry.Config.UseSprinklersAsScarecrows; public IEnumerable GetSprinklerCoverage(Vector2 origin) { - for (int x = -SprinklerRange; x <= SprinklerRange; x++) { - for (int y = -SprinklerRange; y <= SprinklerRange; y++) { + for (int x = -this.SprinklerRange; x <= this.SprinklerRange; x++) { + for (int y = -this.SprinklerRange; y <= this.SprinklerRange; y++) yield return new Vector2(x, y) + origin; - } } } } diff --git a/PrismaticTools/Framework/PrismaticItems.cs b/PrismaticTools/Framework/PrismaticItems.cs index 9b1331d..c29c7a2 100644 --- a/PrismaticTools/Framework/PrismaticItems.cs +++ b/PrismaticTools/Framework/PrismaticItems.cs @@ -1,8 +1,7 @@ -using StardewValley; +using StardewValley; namespace PrismaticTools.Framework { - - public class PrismaticSprinklerItem { + public class PrismaticSprinklerItem { public const int INDEX = 1113; public const string NAME = "Prismatic Sprinkler"; public const int PRICE = 2000; diff --git a/PrismaticTools/Framework/PrismaticPatches.cs b/PrismaticTools/Framework/PrismaticPatches.cs index efbee86..9cc8655 100644 --- a/PrismaticTools/Framework/PrismaticPatches.cs +++ b/PrismaticTools/Framework/PrismaticPatches.cs @@ -1,10 +1,8 @@ -using Harmony; using System.Collections.Generic; -using StardewValley; using Microsoft.Xna.Framework; - -using StardewValley.TerrainFeatures; using Netcode; +using StardewValley; +using StardewValley.TerrainFeatures; using StardewValley.Tools; namespace PrismaticTools.Framework { @@ -65,9 +63,9 @@ public static bool Object_PerformObjectDropInAction(ref Object __instance, ref b } if (__instance.heldObject.Value == null & probe) { if (object1.ParentSheetIndex == 74) { - __instance.heldObject.Value = new Object(); - __result = true; - return false; + __instance.heldObject.Value = new Object(); + __result = true; + return false; } } } @@ -133,7 +131,7 @@ public static void FruitTree_PerformToolAction(ref FruitTree __instance, Tool t, public static void Pickaxe_DoFunction(ref Pickaxe __instance, GameLocation location, int x, int y, int power, Farmer who) { if (__instance.UpgradeLevel == 5) { - if (location.Objects.TryGetValue(new Vector2(x/64, y/64), out Object obj)) { + if (location.Objects.TryGetValue(new Vector2(x / 64, y / 64), out Object obj)) { if (obj.Name == "Stone") { obj.MinutesUntilReady = 0; } diff --git a/PrismaticTools/Framework/Sprinkler.cs b/PrismaticTools/Framework/Sprinkler.cs index 00238b8..635d4a1 100644 --- a/PrismaticTools/Framework/Sprinkler.cs +++ b/PrismaticTools/Framework/Sprinkler.cs @@ -1,18 +1,16 @@ -using Microsoft.Xna.Framework; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using StardewModdingAPI.Events; using StardewValley; using StardewValley.TerrainFeatures; -using StardewModdingAPI.Events; -using System.Collections.Generic; using SObject = StardewValley.Object; namespace PrismaticTools.Framework { - // searches map for any currently placed prismatic sprinklers and: // - waters adjacent tiles // - enables light sources // - optionally makes them act as scarecrows public static class SprinklerInitializer { - public static void Init(IModEvents events) { events.GameLoop.DayStarted += OnDayStarted; events.GameLoop.SaveLoaded += OnSaveLoaded; @@ -57,8 +55,7 @@ private static void OnObjectListChanged(object sender, ObjectListChangedEventArg /// The location containing the sprinkler. /// The sprinkler's tile coordinate within the location. /// The object to check. - private static void TryEnablePrismaticSprinkler(GameLocation location, Vector2 tile, SObject obj) - { + private static void TryEnablePrismaticSprinkler(GameLocation location, Vector2 tile, SObject obj) { if (obj.ParentSheetIndex != PrismaticSprinklerItem.INDEX || !ModEntry.Config.UseSprinklersAsLamps) return; @@ -67,8 +64,7 @@ private static void TryEnablePrismaticSprinkler(GameLocation location, Vector2 t // add light source int id = (int)tile.X * 4000 + (int)tile.Y; - if (!location.sharedLights.ContainsKey(id)) - { + if (!location.sharedLights.ContainsKey(id)) { obj.lightSource = new LightSource(4, tile * Game1.tileSize, 2.0f, Color.Black, id); location.sharedLights.Add(id, obj.lightSource); } @@ -108,4 +104,3 @@ private static void OnDayStarted(object sender, DayStartedEventArgs e) { } } } - diff --git a/PrismaticTools/ModConfig.cs b/PrismaticTools/ModConfig.cs index 6affd87..6f7efbb 100644 --- a/PrismaticTools/ModConfig.cs +++ b/PrismaticTools/ModConfig.cs @@ -1,20 +1,10 @@ - namespace PrismaticTools.Framework { public class ModConfig { - public bool UseSprinklersAsScarecrows { get; set; } - public bool UseSprinklersAsLamps { get; set; } - public int SprinklerRange { get; set; } - public int PrismaticToolLength { get; set; } - public int PrismaticToolWidth { get; set; } - public int PrismaticToolCost { get; set; } - - public ModConfig() { - UseSprinklersAsScarecrows = true; - UseSprinklersAsLamps = true; - SprinklerRange = 3; - PrismaticToolLength = 7; - PrismaticToolWidth = 2; - PrismaticToolCost = 100000; - } + public bool UseSprinklersAsScarecrows { get; set; } = true; + public bool UseSprinklersAsLamps { get; set; } = true; + public int SprinklerRange { get; set; } = 3; + public int PrismaticToolLength { get; set; } = 7; + public int PrismaticToolWidth { get; set; } = 2; + public int PrismaticToolCost { get; set; } = 100000; } } diff --git a/PrismaticTools/ModEntry.cs b/PrismaticTools/ModEntry.cs index 1b492f8..4c5d67b 100644 --- a/PrismaticTools/ModEntry.cs +++ b/PrismaticTools/ModEntry.cs @@ -1,49 +1,41 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - +using System.Collections.Generic; using Harmony; -using StardewValley; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using PrismaticTools.Framework; using StardewModdingAPI; using StardewModdingAPI.Events; - -using PrismaticTools.Framework; -using System.Collections.Generic; -using StardewValley.Objects; -using StardewValley.Locations; +using StardewValley; using StardewValley.TerrainFeatures; using StardewValley.Tools; namespace PrismaticTools { - public class ModEntry : Mod { - - public static IMonitor mon; public static IModHelper ModHelper; public static ModConfig Config; + public static Texture2D ToolsTexture; - public static Texture2D toolsTexture; - private int colorCycleIndex = 0; - private List colors = new List(); + private int colorCycleIndex; + private readonly List colors = new List(); public override void Entry(IModHelper helper) { - mon = Monitor; ModHelper = helper; - Config = Helper.ReadConfig(); + Config = this.Helper.ReadConfig(); - toolsTexture = ModHelper.Content.Load("Assets/tools.png", ContentSource.ModFolder); + ToolsTexture = ModHelper.Content.Load("Assets/tools.png"); - helper.ConsoleCommands.Add("ptools", "Upgrade all tools to prismatic", UpgradeTools); + helper.ConsoleCommands.Add("ptools", "Upgrade all tools to prismatic", this.UpgradeTools); - helper.Events.GameLoop.SaveLoaded += OnSaveLoaded; - helper.Events.GameLoop.UpdateTicked += OnUpdateTicked; - helper.Events.Player.InventoryChanged += OnInventoryChanged; + helper.Events.GameLoop.SaveLoaded += this.OnSaveLoaded; + helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; + helper.Events.Player.InventoryChanged += this.OnInventoryChanged; helper.Content.AssetEditors.Add(new AssetEditor()); SprinklerInitializer.Init(helper.Events); BlacksmithInitializer.Init(helper.Events); - InitColors(); + this.InitColors(); var harmony = HarmonyInstance.Create("stokastic.PrismaticTools"); this.ApplyPatches(harmony); @@ -108,7 +100,7 @@ private void OnUpdateTicked(object sender, UpdateTickedEventArgs e) { Item item; try { item = farmer.Items[farmer.CurrentToolIndex]; - } catch (System.ArgumentOutOfRangeException) { + } catch (System.ArgumentOutOfRangeException) { return; } @@ -118,10 +110,10 @@ private void OnUpdateTicked(object sender, UpdateTickedEventArgs e) { foreach (var light in farmer.currentLocation.sharedLights.Values) { if (light.Identifier == (int)farmer.UniqueMultiplayerID) { - light.color.Value = colors[colorCycleIndex]; + light.color.Value = this.colors[this.colorCycleIndex]; } } - colorCycleIndex = (colorCycleIndex + 1) % colors.Count; + this.colorCycleIndex = (this.colorCycleIndex + 1) % this.colors.Count; } public override object GetApi() { @@ -136,17 +128,17 @@ private void UpgradeTools(string command, string[] args) { } } - // adds lightsources to prismatic bar and sprinkler items in inventory + // adds light sources to prismatic bar and sprinkler items in inventory private void AddLightsToInventoryItems() { if (!Config.UseSprinklersAsLamps) { return; } foreach (Item item in Game1.player.Items) { - if (item is Object) { - if (item.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { - (item as Object).lightSource = new LightSource(LightSource.cauldronLight, new Vector2(0, 0), 2.0f, new Color(0.0f, 0.0f, 0.0f)); - } else if (item.ParentSheetIndex == PrismaticBarItem.INDEX) { - (item as Object).lightSource = new LightSource(LightSource.cauldronLight, new Vector2(0, 0), 1.0f, colors[colorCycleIndex]); + if (item is Object obj) { + if (obj.ParentSheetIndex == PrismaticSprinklerItem.INDEX) { + obj.lightSource = new LightSource(LightSource.cauldronLight, new Vector2(0, 0), 2.0f, new Color(0.0f, 0.0f, 0.0f)); + } else if (obj.ParentSheetIndex == PrismaticBarItem.INDEX) { + obj.lightSource = new LightSource(LightSource.cauldronLight, new Vector2(0, 0), 1.0f, this.colors[this.colorCycleIndex]); } } } @@ -157,7 +149,7 @@ private void AddLightsToInventoryItems() { /// The event arguments. private void OnInventoryChanged(object sender, InventoryChangedEventArgs e) { if (e.IsLocalPlayer) - AddLightsToInventoryItems(); + this.AddLightsToInventoryItems(); } /// Raised after the player loads a save slot and the world is initialised. @@ -171,13 +163,13 @@ private void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { } catch { } } - AddLightsToInventoryItems(); + this.AddLightsToInventoryItems(); } private void InitColors() { int n = 24; - for(int i=0; i