diff options
| -rw-r--r-- | AnodyneArchipelago/Patches/GameplayPatches.cs | 228 | ||||
| -rw-r--r-- | AnodyneArchipelago/Patches/StatePatches.cs | 39 | ||||
| -rw-r--r-- | AnodyneArchipelago/Plugin.cs | 258 |
3 files changed, 268 insertions, 257 deletions
| diff --git a/AnodyneArchipelago/Patches/GameplayPatches.cs b/AnodyneArchipelago/Patches/GameplayPatches.cs new file mode 100644 index 0000000..ada4159 --- /dev/null +++ b/AnodyneArchipelago/Patches/GameplayPatches.cs | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | using AnodyneSharp.Entities.Events; | ||
| 2 | using AnodyneSharp.Entities.Gadget.Treasures; | ||
| 3 | using AnodyneSharp.Entities.Gadget; | ||
| 4 | using AnodyneSharp.Entities.Interactive; | ||
| 5 | using AnodyneSharp.Entities; | ||
| 6 | using AnodyneSharp.Registry; | ||
| 7 | using AnodyneSharp.Utilities; | ||
| 8 | using HarmonyLib; | ||
| 9 | using System; | ||
| 10 | using System.Collections.Generic; | ||
| 11 | using System.Reflection; | ||
| 12 | using Microsoft.Xna.Framework; | ||
| 13 | |||
| 14 | namespace AnodyneArchipelago.Patches | ||
| 15 | { | ||
| 16 | [HarmonyPatch(typeof(TreasureChest), nameof(TreasureChest.PlayerInteraction))] | ||
| 17 | class ChestInteractPatch | ||
| 18 | { | ||
| 19 | static void Prefix(TreasureChest __instance) | ||
| 20 | { | ||
| 21 | string entityId = PatchHelper.GetEntityPreset(typeof(TreasureChest), __instance).EntityID.ToString(); | ||
| 22 | Plugin.Instance.Log.LogInfo($"Touched chest: {entityId}"); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | [HarmonyPatch(typeof(TreasureChest), "SetTreasure")] | ||
| 27 | class ChestSetTreasurePatch | ||
| 28 | { | ||
| 29 | static bool Prefix(TreasureChest __instance) | ||
| 30 | { | ||
| 31 | Guid entityId = PatchHelper.GetEntityPreset(typeof(TreasureChest), __instance).EntityID; | ||
| 32 | if (Locations.LocationsByGuid.ContainsKey(entityId)) | ||
| 33 | { | ||
| 34 | BaseTreasure treasure = new ArchipelagoTreasure(Locations.LocationsByGuid[entityId], __instance.Position); | ||
| 35 | |||
| 36 | FieldInfo treasureField = typeof(TreasureChest).GetField("_treasure", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 37 | treasureField.SetValue(__instance, treasure); | ||
| 38 | |||
| 39 | return false; | ||
| 40 | } | ||
| 41 | |||
| 42 | return true; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | [HarmonyPatch(typeof(Big_Key), nameof(Big_Key.PlayerInteraction))] | ||
| 47 | class BigKeyTouchPatch | ||
| 48 | { | ||
| 49 | // We basically just rewrite this method, because we need to get rid of the part that adds the key to the inventory. | ||
| 50 | static bool Prefix(Big_Key __instance, ref bool __result) | ||
| 51 | { | ||
| 52 | MethodInfo statesMethod = typeof(Big_Key).GetMethod("States", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 53 | |||
| 54 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(Big_Key), __instance); | ||
| 55 | preset.Alive = false; | ||
| 56 | __instance.Solid = false; | ||
| 57 | GlobalState.StartCutscene = (IEnumerator<AnodyneSharp.States.CutsceneState.CutsceneEvent>)statesMethod.Invoke(__instance, new object[] { }); | ||
| 58 | __result = true; | ||
| 59 | return false; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | [HarmonyPatch(typeof(Big_Key), "States")] | ||
| 64 | class BigKeyStatesPatch | ||
| 65 | { | ||
| 66 | static void Postfix(Big_Key __instance) | ||
| 67 | { | ||
| 68 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(Big_Key), __instance); | ||
| 69 | |||
| 70 | if (preset.Frame == 0) | ||
| 71 | { | ||
| 72 | ArchipelagoManager.SendLocation("Temple of the Seeing One - Green Key"); | ||
| 73 | } | ||
| 74 | else if (preset.Frame == 1) | ||
| 75 | { | ||
| 76 | ArchipelagoManager.SendLocation("Red Grotto - Red Key"); | ||
| 77 | } | ||
| 78 | else if (preset.Frame == 2) | ||
| 79 | { | ||
| 80 | ArchipelagoManager.SendLocation("Mountain Cavern - Blue Key"); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | [HarmonyPatch(typeof(HealthCicadaSentinel), nameof(HealthCicadaSentinel.Collided))] | ||
| 86 | class HealthCicadaInteractPatch | ||
| 87 | { | ||
| 88 | static void Prefix(TreasureChest __instance) | ||
| 89 | { | ||
| 90 | Type hcsType = typeof(HealthCicadaSentinel); | ||
| 91 | FieldInfo childField = hcsType.GetField("_child", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 92 | HealthCicada healthCicada = (HealthCicada)childField.GetValue(__instance); | ||
| 93 | |||
| 94 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(HealthCicada), healthCicada); | ||
| 95 | Plugin.Instance.Log.LogInfo($"Touched cicada: {preset.EntityID.ToString()}"); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | [HarmonyPatch(typeof(HealthCicada), nameof(HealthCicada.Update))] | ||
| 100 | class HealthCicadaUpdatePatch | ||
| 101 | { | ||
| 102 | static void Postfix(HealthCicada __instance) | ||
| 103 | { | ||
| 104 | Type cicadaType = typeof(HealthCicada); | ||
| 105 | FieldInfo chirpField = cicadaType.GetField("_chirp", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 106 | FieldInfo sentinelField = cicadaType.GetField("_sentinel", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 107 | |||
| 108 | HealthCicadaSentinel sentinel = (HealthCicadaSentinel)sentinelField.GetValue(__instance); | ||
| 109 | Type hcsType = typeof(HealthCicadaSentinel); | ||
| 110 | FieldInfo flyDistanceField = hcsType.GetField("_flyDistance", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 111 | float flyDistance = (float)flyDistanceField.GetValue(sentinel); | ||
| 112 | |||
| 113 | if (__instance.visible && !(bool)chirpField.GetValue(__instance) && flyDistance > 0) | ||
| 114 | { | ||
| 115 | flyDistanceField.SetValue(sentinel, 0f); | ||
| 116 | |||
| 117 | FieldInfo stateField = cicadaType.GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 118 | stateField.SetValue(__instance, StateLogic(__instance)); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | static IEnumerator<string> StateLogic(HealthCicada healthCicada) | ||
| 123 | { | ||
| 124 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(HealthCicada), healthCicada); | ||
| 125 | |||
| 126 | while (!MathUtilities.MoveTo(ref healthCicada.opacity, 0.0f, 0.6f)) | ||
| 127 | yield return "FadingOut"; | ||
| 128 | preset.Alive = false; | ||
| 129 | |||
| 130 | FieldInfo sentinelField = typeof(HealthCicada).GetField("_sentinel", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 131 | HealthCicadaSentinel sentinel = (HealthCicadaSentinel)sentinelField.GetValue(healthCicada); | ||
| 132 | |||
| 133 | sentinel.exists = false; | ||
| 134 | |||
| 135 | if (Locations.LocationsByGuid.ContainsKey(preset.EntityID)) | ||
| 136 | { | ||
| 137 | ArchipelagoManager.SendLocation(Locations.LocationsByGuid[preset.EntityID]); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | [HarmonyPatch(typeof(EntityPreset), nameof(EntityPreset.Create))] | ||
| 143 | class EntityPresetCreatePatch | ||
| 144 | { | ||
| 145 | static void Postfix(EntityPreset __instance, Entity __result) | ||
| 146 | { | ||
| 147 | if (__instance.Type.FullName == "AnodyneSharp.Entities.Interactive.DungeonStatue") | ||
| 148 | { | ||
| 149 | __result.Position = __instance.Position + new Vector2(1f, 32f); | ||
| 150 | |||
| 151 | string eventName = "StatueMoved_"; | ||
| 152 | Facing moveDir = Facing.RIGHT; | ||
| 153 | if (__instance.Frame == 0) | ||
| 154 | { | ||
| 155 | eventName += "Temple"; | ||
| 156 | moveDir = Facing.UP; | ||
| 157 | } | ||
| 158 | else if (__instance.Frame == 1) | ||
| 159 | { | ||
| 160 | eventName += "Grotto"; | ||
| 161 | } | ||
| 162 | else if (__instance.Frame == 2) | ||
| 163 | { | ||
| 164 | eventName += "Mountain"; | ||
| 165 | } | ||
| 166 | |||
| 167 | if (GlobalState.events.GetEvent(eventName) > 0) | ||
| 168 | { | ||
| 169 | __result.Position += Entity.FacingDirection(moveDir) * 32f; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | else if (__instance.Type.FullName.StartsWith("AnodyneSharp.Entities.Decorations.RedCave")) | ||
| 173 | { | ||
| 174 | string side = __instance.Type.FullName.Substring(41); | ||
| 175 | int requiredGrottos = 0; | ||
| 176 | if (side == "Left") | ||
| 177 | { | ||
| 178 | requiredGrottos = 1; | ||
| 179 | } | ||
| 180 | else if (side == "Right") | ||
| 181 | { | ||
| 182 | requiredGrottos = 2; | ||
| 183 | } | ||
| 184 | else if (side == "North") | ||
| 185 | { | ||
| 186 | requiredGrottos = 3; | ||
| 187 | } | ||
| 188 | |||
| 189 | if (GlobalState.events.GetEvent("ProgressiveRedGrotto") < requiredGrottos) | ||
| 190 | { | ||
| 191 | __result.exists = false; | ||
| 192 | GlobalState.SpawnEntity((Entity)new DoorToggle(__result.Position, __result.width, __result.height)); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | else if (__instance.Type.FullName == "AnodyneSharp.Entities.Interactive.Npc.MitraCliff") | ||
| 196 | { | ||
| 197 | // We want to get rid of this scene entirely. | ||
| 198 | __instance.Alive = false; | ||
| 199 | __result.exists = false; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | [HarmonyPatch] | ||
| 205 | class BreakChainPatch | ||
| 206 | { | ||
| 207 | static MethodInfo TargetMethod() | ||
| 208 | { | ||
| 209 | return typeof(Red_Pillar).GetNestedType("Chain", BindingFlags.NonPublic).GetMethod("Collided"); | ||
| 210 | } | ||
| 211 | |||
| 212 | static void Postfix(object __instance) | ||
| 213 | { | ||
| 214 | Type chainType = typeof(Red_Pillar).GetNestedType("Chain", BindingFlags.NonPublic); | ||
| 215 | FieldInfo parentField = chainType.GetField("_parent", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 216 | |||
| 217 | Red_Pillar redPillar = (Red_Pillar)parentField.GetValue(__instance); | ||
| 218 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(Red_Pillar), redPillar); | ||
| 219 | |||
| 220 | Plugin.Instance.Log.LogInfo($"Broke red chain: {preset.EntityID.ToString()}"); | ||
| 221 | |||
| 222 | if (Locations.LocationsByGuid.ContainsKey(preset.EntityID)) | ||
| 223 | { | ||
| 224 | ArchipelagoManager.SendLocation(Locations.LocationsByGuid[preset.EntityID]); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| diff --git a/AnodyneArchipelago/Patches/StatePatches.cs b/AnodyneArchipelago/Patches/StatePatches.cs new file mode 100644 index 0000000..f6acc62 --- /dev/null +++ b/AnodyneArchipelago/Patches/StatePatches.cs | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | using AnodyneSharp.Entities; | ||
| 2 | using AnodyneSharp.Registry; | ||
| 3 | using AnodyneSharp.States; | ||
| 4 | using AnodyneSharp; | ||
| 5 | using HarmonyLib; | ||
| 6 | using System.Reflection; | ||
| 7 | |||
| 8 | namespace AnodyneArchipelago.Patches | ||
| 9 | { | ||
| 10 | [HarmonyPatch(typeof(AnodyneGame), "Update")] | ||
| 11 | class GameUpdatePatch | ||
| 12 | { | ||
| 13 | static void Postfix() | ||
| 14 | { | ||
| 15 | ArchipelagoManager.Update(); | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | [HarmonyPatch(typeof(PlayState), nameof(PlayState.Create))] | ||
| 20 | class PlayStateCreatePatch | ||
| 21 | { | ||
| 22 | static void Prefix(PlayState __instance) | ||
| 23 | { | ||
| 24 | // Get player for later access. | ||
| 25 | FieldInfo playerField = typeof(PlayState).GetField("_player", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 26 | Plugin.Player = (Player)playerField.GetValue(__instance); | ||
| 27 | |||
| 28 | // Handle Red Grotto stuff. | ||
| 29 | GlobalState.events.SetEvent("red_cave_l_ss", 999); | ||
| 30 | GlobalState.events.SetEvent("red_cave_n_ss", 999); | ||
| 31 | GlobalState.events.SetEvent("red_cave_r_ss", 999); | ||
| 32 | |||
| 33 | // Connect to archipelago. | ||
| 34 | Plugin.Instance.Log.LogInfo("Connecting to Archipelago!"); | ||
| 35 | |||
| 36 | ArchipelagoManager.Connect("localhost:38281", "Anodyne", ""); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| diff --git a/AnodyneArchipelago/Plugin.cs b/AnodyneArchipelago/Plugin.cs index 26f1274..1f6e7ea 100644 --- a/AnodyneArchipelago/Plugin.cs +++ b/AnodyneArchipelago/Plugin.cs | |||
| @@ -1,21 +1,8 @@ | |||
| 1 | using AnodyneArchipelago.Patches; | 1 | using AnodyneSharp.Entities; |
| 2 | using AnodyneSharp; | ||
| 3 | using AnodyneSharp.Entities; | ||
| 4 | using AnodyneSharp.Entities.Events; | ||
| 5 | using AnodyneSharp.Entities.Gadget; | ||
| 6 | using AnodyneSharp.Entities.Gadget.Treasures; | ||
| 7 | using AnodyneSharp.Entities.Interactive; | ||
| 8 | using AnodyneSharp.Registry; | ||
| 9 | using AnodyneSharp.States; | ||
| 10 | using AnodyneSharp.Utilities; | ||
| 11 | using BepInEx; | 2 | using BepInEx; |
| 12 | using BepInEx.NET.Common; | 3 | using BepInEx.NET.Common; |
| 13 | using HarmonyLib; | 4 | using HarmonyLib; |
| 14 | using HarmonyLib.Tools; | 5 | using HarmonyLib.Tools; |
| 15 | using Microsoft.Xna.Framework; | ||
| 16 | using System; | ||
| 17 | using System.Collections; | ||
| 18 | using System.Collections.Generic; | ||
| 19 | using System.Reflection; | 6 | using System.Reflection; |
| 20 | 7 | ||
| 21 | namespace AnodyneArchipelago | 8 | namespace AnodyneArchipelago |
| @@ -40,247 +27,4 @@ namespace AnodyneArchipelago | |||
| 40 | Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); | 27 | Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); |
| 41 | } | 28 | } |
| 42 | } | 29 | } |
| 43 | |||
| 44 | [HarmonyPatch(typeof(AnodyneGame), "Update")] | ||
| 45 | class GameUpdatePatch | ||
| 46 | { | ||
| 47 | static void Postfix() | ||
| 48 | { | ||
| 49 | ArchipelagoManager.Update(); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | [HarmonyPatch(typeof(PlayState), nameof(PlayState.Create))] | ||
| 54 | class PlayStateCreatePatch | ||
| 55 | { | ||
| 56 | static void Prefix(PlayState __instance) | ||
| 57 | { | ||
| 58 | // Get player for later access. | ||
| 59 | FieldInfo playerField = typeof(PlayState).GetField("_player", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 60 | Plugin.Player = (Player)playerField.GetValue(__instance); | ||
| 61 | |||
| 62 | // Handle Red Grotto stuff. | ||
| 63 | GlobalState.events.SetEvent("red_cave_l_ss", 999); | ||
| 64 | GlobalState.events.SetEvent("red_cave_n_ss", 999); | ||
| 65 | GlobalState.events.SetEvent("red_cave_r_ss", 999); | ||
| 66 | |||
| 67 | // Connect to archipelago. | ||
| 68 | Plugin.Instance.Log.LogInfo("Connecting to Archipelago!"); | ||
| 69 | |||
| 70 | ArchipelagoManager.Connect("localhost:38281", "Anodyne", ""); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | [HarmonyPatch(typeof(TreasureChest), nameof(TreasureChest.PlayerInteraction))] | ||
| 75 | class ChestInteractPatch | ||
| 76 | { | ||
| 77 | static void Prefix(TreasureChest __instance) | ||
| 78 | { | ||
| 79 | string entityId = PatchHelper.GetEntityPreset(typeof(TreasureChest), __instance).EntityID.ToString(); | ||
| 80 | Plugin.Instance.Log.LogInfo($"Touched chest: {entityId}"); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | [HarmonyPatch(typeof(TreasureChest), "SetTreasure")] | ||
| 85 | class ChestSetTreasurePatch | ||
| 86 | { | ||
| 87 | static bool Prefix(TreasureChest __instance) | ||
| 88 | { | ||
| 89 | Guid entityId = PatchHelper.GetEntityPreset(typeof(TreasureChest), __instance).EntityID; | ||
| 90 | if (Locations.LocationsByGuid.ContainsKey(entityId)) | ||
| 91 | { | ||
| 92 | BaseTreasure treasure = new ArchipelagoTreasure(Locations.LocationsByGuid[entityId], __instance.Position); | ||
| 93 | |||
| 94 | FieldInfo treasureField = typeof(TreasureChest).GetField("_treasure", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 95 | treasureField.SetValue(__instance, treasure); | ||
| 96 | |||
| 97 | return false; | ||
| 98 | } | ||
| 99 | |||
| 100 | return true; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | [HarmonyPatch(typeof(Big_Key), nameof(Big_Key.PlayerInteraction))] | ||
| 105 | class BigKeyTouchPatch | ||
| 106 | { | ||
| 107 | // We basically just rewrite this method, because we need to get rid of the part that adds the key to the inventory. | ||
| 108 | static bool Prefix(Big_Key __instance, ref bool __result) | ||
| 109 | { | ||
| 110 | MethodInfo statesMethod = typeof(Big_Key).GetMethod("States", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 111 | |||
| 112 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(Big_Key), __instance); | ||
| 113 | preset.Alive = false; | ||
| 114 | __instance.Solid = false; | ||
| 115 | GlobalState.StartCutscene = (IEnumerator<AnodyneSharp.States.CutsceneState.CutsceneEvent>)statesMethod.Invoke(__instance, new object[] { }); | ||
| 116 | __result = true; | ||
| 117 | return false; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | [HarmonyPatch(typeof(Big_Key), "States")] | ||
| 122 | class BigKeyStatesPatch | ||
| 123 | { | ||
| 124 | static void Postfix(Big_Key __instance) | ||
| 125 | { | ||
| 126 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(Big_Key), __instance); | ||
| 127 | |||
| 128 | if (preset.Frame == 0) | ||
| 129 | { | ||
| 130 | ArchipelagoManager.SendLocation("Temple of the Seeing One - Green Key"); | ||
| 131 | } | ||
| 132 | else if (preset.Frame == 1) | ||
| 133 | { | ||
| 134 | ArchipelagoManager.SendLocation("Red Grotto - Red Key"); | ||
| 135 | } | ||
| 136 | else if (preset.Frame == 2) | ||
| 137 | { | ||
| 138 | ArchipelagoManager.SendLocation("Mountain Cavern - Blue Key"); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | [HarmonyPatch(typeof(HealthCicadaSentinel), nameof(HealthCicadaSentinel.Collided))] | ||
| 144 | class HealthCicadaInteractPatch | ||
| 145 | { | ||
| 146 | static void Prefix(TreasureChest __instance) | ||
| 147 | { | ||
| 148 | Type hcsType = typeof(HealthCicadaSentinel); | ||
| 149 | FieldInfo childField = hcsType.GetField("_child", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 150 | HealthCicada healthCicada = (HealthCicada)childField.GetValue(__instance); | ||
| 151 | |||
| 152 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(HealthCicada), healthCicada); | ||
| 153 | Plugin.Instance.Log.LogInfo($"Touched cicada: {preset.EntityID.ToString()}"); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | [HarmonyPatch(typeof(HealthCicada), nameof(HealthCicada.Update))] | ||
| 158 | class HealthCicadaUpdatePatch | ||
| 159 | { | ||
| 160 | static void Postfix(HealthCicada __instance) | ||
| 161 | { | ||
| 162 | Type cicadaType = typeof(HealthCicada); | ||
| 163 | FieldInfo chirpField = cicadaType.GetField("_chirp", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 164 | FieldInfo sentinelField = cicadaType.GetField("_sentinel", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 165 | |||
| 166 | HealthCicadaSentinel sentinel = (HealthCicadaSentinel)sentinelField.GetValue(__instance); | ||
| 167 | Type hcsType = typeof(HealthCicadaSentinel); | ||
| 168 | FieldInfo flyDistanceField = hcsType.GetField("_flyDistance", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 169 | float flyDistance = (float)flyDistanceField.GetValue(sentinel); | ||
| 170 | |||
| 171 | if (__instance.visible && !(bool)chirpField.GetValue(__instance) && flyDistance > 0) | ||
| 172 | { | ||
| 173 | flyDistanceField.SetValue(sentinel, 0f); | ||
| 174 | |||
| 175 | FieldInfo stateField = cicadaType.GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 176 | stateField.SetValue(__instance, StateLogic(__instance)); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static IEnumerator<string> StateLogic(HealthCicada healthCicada) | ||
| 181 | { | ||
| 182 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(HealthCicada), healthCicada); | ||
| 183 | |||
| 184 | while (!MathUtilities.MoveTo(ref healthCicada.opacity, 0.0f, 0.6f)) | ||
| 185 | yield return "FadingOut"; | ||
| 186 | preset.Alive = false; | ||
| 187 | |||
| 188 | FieldInfo sentinelField = typeof(HealthCicada).GetField("_sentinel", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 189 | HealthCicadaSentinel sentinel = (HealthCicadaSentinel)sentinelField.GetValue(healthCicada); | ||
| 190 | |||
| 191 | sentinel.exists = false; | ||
| 192 | |||
| 193 | if (Locations.LocationsByGuid.ContainsKey(preset.EntityID)) | ||
| 194 | { | ||
| 195 | ArchipelagoManager.SendLocation(Locations.LocationsByGuid[preset.EntityID]); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | [HarmonyPatch(typeof(EntityPreset), nameof(EntityPreset.Create))] | ||
| 201 | class EntityPresetCreatePatch | ||
| 202 | { | ||
| 203 | static void Postfix(EntityPreset __instance, Entity __result) | ||
| 204 | { | ||
| 205 | if (__instance.Type.FullName == "AnodyneSharp.Entities.Interactive.DungeonStatue") | ||
| 206 | { | ||
| 207 | __result.Position = __instance.Position + new Vector2(1f, 32f); | ||
| 208 | |||
| 209 | string eventName = "StatueMoved_"; | ||
| 210 | Facing moveDir = Facing.RIGHT; | ||
| 211 | if (__instance.Frame == 0) | ||
| 212 | { | ||
| 213 | eventName += "Temple"; | ||
| 214 | moveDir = Facing.UP; | ||
| 215 | } | ||
| 216 | else if (__instance.Frame == 1) | ||
| 217 | { | ||
| 218 | eventName += "Grotto"; | ||
| 219 | } | ||
| 220 | else if (__instance.Frame == 2) | ||
| 221 | { | ||
| 222 | eventName += "Mountain"; | ||
| 223 | } | ||
| 224 | |||
| 225 | if (GlobalState.events.GetEvent(eventName) > 0) | ||
| 226 | { | ||
| 227 | __result.Position += Entity.FacingDirection(moveDir) * 32f; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | else if (__instance.Type.FullName.StartsWith("AnodyneSharp.Entities.Decorations.RedCave")) | ||
| 231 | { | ||
| 232 | string side = __instance.Type.FullName.Substring(41); | ||
| 233 | int requiredGrottos = 0; | ||
| 234 | if (side == "Left") | ||
| 235 | { | ||
| 236 | requiredGrottos = 1; | ||
| 237 | } | ||
| 238 | else if (side == "Right") | ||
| 239 | { | ||
| 240 | requiredGrottos = 2; | ||
| 241 | } | ||
| 242 | else if (side == "North") | ||
| 243 | { | ||
| 244 | requiredGrottos = 3; | ||
| 245 | } | ||
| 246 | |||
| 247 | if (GlobalState.events.GetEvent("ProgressiveRedGrotto") < requiredGrottos) | ||
| 248 | { | ||
| 249 | __result.exists = false; | ||
| 250 | GlobalState.SpawnEntity((Entity)new DoorToggle(__result.Position, __result.width, __result.height)); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | else if (__instance.Type.FullName == "AnodyneSharp.Entities.Interactive.Npc.MitraCliff") | ||
| 254 | { | ||
| 255 | // We want to get rid of this scene entirely. | ||
| 256 | __instance.Alive = false; | ||
| 257 | __result.exists = false; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | [HarmonyPatch] | ||
| 263 | class BreakChainPatch | ||
| 264 | { | ||
| 265 | static MethodInfo TargetMethod() | ||
| 266 | { | ||
| 267 | return typeof(Red_Pillar).GetNestedType("Chain", BindingFlags.NonPublic).GetMethod("Collided"); | ||
| 268 | } | ||
| 269 | |||
| 270 | static void Postfix(object __instance) | ||
| 271 | { | ||
| 272 | Type chainType = typeof(Red_Pillar).GetNestedType("Chain", BindingFlags.NonPublic); | ||
| 273 | FieldInfo parentField = chainType.GetField("_parent", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 274 | |||
| 275 | Red_Pillar redPillar = (Red_Pillar)parentField.GetValue(__instance); | ||
| 276 | EntityPreset preset = PatchHelper.GetEntityPreset(typeof(Red_Pillar), redPillar); | ||
| 277 | |||
| 278 | Plugin.Instance.Log.LogInfo($"Broke red chain: {preset.EntityID.ToString()}"); | ||
| 279 | |||
| 280 | if (Locations.LocationsByGuid.ContainsKey(preset.EntityID)) | ||
| 281 | { | ||
| 282 | ArchipelagoManager.SendLocation(Locations.LocationsByGuid[preset.EntityID]); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | } | 30 | } |
