about summary refs log tree commit diff stats
path: root/AnodyneArchipelago/Patches/GameplayPatches.cs
diff options
context:
space:
mode:
Diffstat (limited to 'AnodyneArchipelago/Patches/GameplayPatches.cs')
-rw-r--r--AnodyneArchipelago/Patches/GameplayPatches.cs228
1 files changed, 228 insertions, 0 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 @@
1using AnodyneSharp.Entities.Events;
2using AnodyneSharp.Entities.Gadget.Treasures;
3using AnodyneSharp.Entities.Gadget;
4using AnodyneSharp.Entities.Interactive;
5using AnodyneSharp.Entities;
6using AnodyneSharp.Registry;
7using AnodyneSharp.Utilities;
8using HarmonyLib;
9using System;
10using System.Collections.Generic;
11using System.Reflection;
12using Microsoft.Xna.Framework;
13
14namespace 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}