summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-02-23 14:00:17 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2025-02-23 14:00:17 -0500
commitc0ad40a3d43e83f35432d12e8b55d90c1865c264 (patch)
treeb1a91e9d697cb548ba048e8badbaccaf2800b065
parent22fd4098d048b6833f1993604f17144eadf3dea3 (diff)
downloadmanifold-garden-archipelago-c0ad40a3d43e83f35432d12e8b55d90c1865c264.tar.gz
manifold-garden-archipelago-c0ad40a3d43e83f35432d12e8b55d90c1865c264.tar.bz2
manifold-garden-archipelago-c0ad40a3d43e83f35432d12e8b55d90c1865c264.zip
A bunch of things
- Requirement decisions now have three states: yes, no, and maybe. Maybe means that the state of the game object in question hasn't been detected yet, so acting on the event that checked the requirement should be deferred. This was intended to fix the inverted pad checks in Pyramid, but it does not seem to have worked. Questioning reverting this part.
- Fixed the doors in W018.
- Smoke walls now work, sort of. If the cube is still on the pad, loading the game in that room will cause the wall to close (leaving and re-entering the room dismisses it thought). Putting the cube back on the pad will also close it again. Need to fix later.
- More patches that record gameplay state without interaction from the player and call listeners for those objects. e.g. buttons getting pressed by the game when loaded in, as opposed to when pressed by the player. Pads have been tweaked like this too.
- When opening a door, the mod now also invokes the animator. This fixes the problem where doors would appear to be closed when re-entering a room, even though you could still walk through them.
-rw-r--r--ArchipelagoManager.cs1
-rw-r--r--GameData.cs2
-rw-r--r--GameState.cs37
-rw-r--r--GameplayPatches.cs195
-rw-r--r--Requirements.cs117
-rw-r--r--SlotSave.cs16
-rw-r--r--game_data.yaml38
7 files changed, 309 insertions, 97 deletions
diff --git a/ArchipelagoManager.cs b/ArchipelagoManager.cs index 611ef30..998e2d9 100644 --- a/ArchipelagoManager.cs +++ b/ArchipelagoManager.cs
@@ -87,6 +87,7 @@ namespace ManifoldGardenArchipelago
87 87
88 if (GameData.listenersByItem.TryGetValue(itemName, out var listeners)) 88 if (GameData.listenersByItem.TryGetValue(itemName, out var listeners))
89 { 89 {
90 //Plugin.Logger.LogInfo($"Evaluating for {itemName}");
90 GameState.EvaluateGameStateListeners(listeners); 91 GameState.EvaluateGameStateListeners(listeners);
91 } 92 }
92 } 93 }
diff --git a/GameData.cs b/GameData.cs index 9ec511e..6b5eddc 100644 --- a/GameData.cs +++ b/GameData.cs
@@ -372,6 +372,8 @@ namespace ManifoldGardenArchipelago
372 Requirement req = ParseRequirement(scenePair.Key, (Dictionary<object, object>)smokePair.Value); 372 Requirement req = ParseRequirement(scenePair.Key, (Dictionary<object, object>)smokePair.Value);
373 sceneDescription.smokeWalls[sir.index] = req; 373 sceneDescription.smokeWalls[sir.index] = req;
374 374
375 Plugin.Logger.LogInfo($"Smoke {sir} requirements: {req}");
376
375 foreach (var reqScene in req.references.scenes) 377 foreach (var reqScene in req.references.scenes)
376 { 378 {
377 GetOrAddListeners(listenersByScene, reqScene).smokeWalls[sir] = req; 379 GetOrAddListeners(listenersByScene, reqScene).smokeWalls[sir] = req;
diff --git a/GameState.cs b/GameState.cs index d3bea06..bdf5760 100644 --- a/GameState.cs +++ b/GameState.cs
@@ -112,7 +112,7 @@ namespace ManifoldGardenArchipelago
112 { 112 {
113 foreach (var location in listeners.locations) 113 foreach (var location in listeners.locations)
114 { 114 {
115 if (location.Value.Check()) 115 if (location.Value.Check() == Requirement.Decision.Yes)
116 { 116 {
117 Plugin.archipelagoManager.CheckLocation(location.Key); 117 Plugin.archipelagoManager.CheckLocation(location.Key);
118 } 118 }
@@ -120,8 +120,14 @@ namespace ManifoldGardenArchipelago
120 120
121 foreach (var door in listeners.doors) 121 foreach (var door in listeners.doors)
122 { 122 {
123 bool shouldOpen = door.Value.Check(); 123 Requirement.Decision decision = door.Value.Check();
124 Plugin.Logger.LogInfo($"{door.Key}: {door.Value} -> {shouldOpen}"); 124 if (decision == Requirement.Decision.Maybe)
125 {
126 continue;
127 }
128
129 bool shouldOpen = (decision == Requirement.Decision.Yes);
130 //Plugin.Logger.LogInfo($"{door.Key}: {door.Value} -> {shouldOpen}");
125 131
126 if (SceneManager.GetSceneByName(door.Key.scene) is Scene doorScene && doorScene.isLoaded) 132 if (SceneManager.GetSceneByName(door.Key.scene) is Scene doorScene && doorScene.isLoaded)
127 { 133 {
@@ -142,11 +148,34 @@ namespace ManifoldGardenArchipelago
142 } 148 }
143 } 149 }
144 150
151 foreach (var smokeWall in listeners.smokeWalls)
152 {
153 Requirement.Decision decision = smokeWall.Value.Check();
154 if (decision == Requirement.Decision.Maybe)
155 {
156 continue;
157 }
158
159 bool shouldOpen = (decision == Requirement.Decision.Yes);
160 //Plugin.Logger.LogInfo($"{smokeWall.Key}: {smokeWall.Value} -> {shouldOpen}");
145 161
162 if (SceneManager.GetSceneByName(smokeWall.Key.scene) is Scene smokeScene && smokeScene.isLoaded)
163 {
164 LevelSystems levelSystems = GetLevelSystems(smokeScene);
165 if (levelSystems.isActiveAndEnabled)
166 {
167 SolidStateController ldc = levelSystems.chainListeners[smokeWall.Key.index].GetComponent<SolidStateController>();
168 ldc.chains.Clear();
169
170 FieldInfo fieldInfo = typeof(SolidStateController).GetField("m_isSolid", BindingFlags.Instance | BindingFlags.NonPublic);
171 fieldInfo.SetValue(ldc, !shouldOpen);
172 }
173 }
174 }
146 175
147 foreach (var worldGrow in listeners.worldGrows) 176 foreach (var worldGrow in listeners.worldGrows)
148 { 177 {
149 if (worldGrow.Value.Check()) 178 if (worldGrow.Value.Check() == Requirement.Decision.Yes)
150 { 179 {
151 if (SceneManager.GetSceneByName(worldGrow.Key.scene) is Scene gardenScene && gardenScene.isLoaded) 180 if (SceneManager.GetSceneByName(worldGrow.Key.scene) is Scene gardenScene && gardenScene.isLoaded)
152 { 181 {
diff --git a/GameplayPatches.cs b/GameplayPatches.cs index c21bf97..3090a98 100644 --- a/GameplayPatches.cs +++ b/GameplayPatches.cs
@@ -1,5 +1,6 @@
1using HarmonyLib; 1using HarmonyLib;
2using System.Reflection; 2using System.Reflection;
3using UnityEngine;
3 4
4namespace ManifoldGardenArchipelago 5namespace ManifoldGardenArchipelago
5{ 6{
@@ -14,9 +15,16 @@ namespace ManifoldGardenArchipelago
14 { 15 {
15 if (sceneDescription.doors.TryGetValue(sir.index, out var requirement)) 16 if (sceneDescription.doors.TryGetValue(sir.index, out var requirement))
16 { 17 {
17 if (open != requirement.Check()) 18 Requirement.Decision decision = requirement.Check();
19
20 if (decision != Requirement.Decision.Maybe)
18 { 21 {
19 return false; 22 bool shouldOpen = (decision == Requirement.Decision.Yes);
23
24 if (open != shouldOpen)
25 {
26 return false;
27 }
20 } 28 }
21 } 29 }
22 } 30 }
@@ -38,15 +46,27 @@ namespace ManifoldGardenArchipelago
38 return; 46 return;
39 } 47 }
40 48
41 if (setPressed) 49 Plugin.slotSave.ActivatedButtons[sir] = setPressed;
42 { 50
43 Plugin.slotSave.ActivatedButtons.Add(sir); 51 GameState.EvaluateGameStateListeners(listeners);
44 } 52 }
45 else 53 }
54
55 [HarmonyPatch(typeof(ButtonLineActivator), "ForceButtonPressedImmediately")]
56 static class ButtonLineActivatorForceButtonPressedImmediatelyPatch
57 {
58 static void Prefix(ButtonLineActivator __instance, bool _pressed)
59 {
60 SceneItemReference sir = GameState.GetButtonSceneReference(__instance);
61 Plugin.Logger.LogInfo($"Button {sir} forced state {_pressed}");
62
63 if (!GameData.listenersByButton.TryGetValue(sir, out GameStateListeners listeners))
46 { 64 {
47 Plugin.slotSave.ActivatedButtons.Remove(sir); 65 return;
48 } 66 }
49 67
68 Plugin.slotSave.ActivatedButtons[sir] = _pressed;
69
50 GameState.EvaluateGameStateListeners(listeners); 70 GameState.EvaluateGameStateListeners(listeners);
51 } 71 }
52 } 72 }
@@ -64,14 +84,7 @@ namespace ManifoldGardenArchipelago
64 return; 84 return;
65 } 85 }
66 86
67 if (active) 87 Plugin.slotSave.ActivatedSockets[sir] = active;
68 {
69 Plugin.slotSave.ActivatedSockets.Add(sir);
70 }
71 else
72 {
73 Plugin.slotSave.ActivatedSockets.Remove(sir);
74 }
75 88
76 GameState.EvaluateGameStateListeners(listeners); 89 GameState.EvaluateGameStateListeners(listeners);
77 } 90 }
@@ -90,15 +103,46 @@ namespace ManifoldGardenArchipelago
90 return; 103 return;
91 } 104 }
92 105
93 if (setActive) 106 Plugin.slotSave.ActivatedPads[sir] = setActive;
107
108 GameState.EvaluateGameStateListeners(listeners);
109 }
110 }
111
112 [HarmonyPatch(typeof(CubeLineActivator), "ForceActivatorToTurnOnAsCorrectCubeOnSwitch")]
113 static class CubeLineActivatorForceActivatorToTurnOnAsCorrectCubeOnSwitchPatch
114 {
115 static void Prefix(CubeLineActivator __instance)
116 {
117 SceneItemReference sir = GameState.GetPadSceneReference(__instance);
118 Plugin.Logger.LogInfo($"Pad {sir} forced on");
119
120 if (!GameData.listenersByPad.TryGetValue(sir, out GameStateListeners listeners))
94 { 121 {
95 Plugin.slotSave.ActivatedPads.Add(sir); 122 return;
96 } 123 }
97 else 124
125 Plugin.slotSave.ActivatedPads[sir] = true;
126
127 GameState.EvaluateGameStateListeners(listeners);
128 }
129 }
130
131 [HarmonyPatch(typeof(CubeLineActivator), "ForceActivatorToTurnOffAsCorrectCubeNotOnSwitch")]
132 static class CubeLineActivatorForceActivatorToTurnOffAsCorrectCubeNotOnSwitchPatch
133 {
134 static void Prefix(CubeLineActivator __instance)
135 {
136 SceneItemReference sir = GameState.GetPadSceneReference(__instance);
137 Plugin.Logger.LogInfo($"Pad {sir} forced off");
138
139 if (!GameData.listenersByPad.TryGetValue(sir, out GameStateListeners listeners))
98 { 140 {
99 Plugin.slotSave.ActivatedPads.Remove(sir); 141 return;
100 } 142 }
101 143
144 Plugin.slotSave.ActivatedPads[sir] = false;
145
102 GameState.EvaluateGameStateListeners(listeners); 146 GameState.EvaluateGameStateListeners(listeners);
103 } 147 }
104 } 148 }
@@ -109,21 +153,14 @@ namespace ManifoldGardenArchipelago
109 static void Prefix(WaterDetector __instance, bool setActive) 153 static void Prefix(WaterDetector __instance, bool setActive)
110 { 154 {
111 SceneItemReference sir = GameState.GetWaterwheelSceneReference(__instance); 155 SceneItemReference sir = GameState.GetWaterwheelSceneReference(__instance);
112 Plugin.Logger.LogInfo($"Waterwheel {sir} state {setActive}"); 156 //Plugin.Logger.LogInfo($"Waterwheel {sir} state {setActive}");
113 157
114 if (!GameData.listenersByWaterwheel.TryGetValue(sir, out GameStateListeners listeners)) 158 if (!GameData.listenersByWaterwheel.TryGetValue(sir, out GameStateListeners listeners))
115 { 159 {
116 return; 160 return;
117 } 161 }
118 162
119 if (setActive) 163 Plugin.slotSave.ActivatedWaterwheels[sir] = setActive;
120 {
121 Plugin.slotSave.ActivatedWaterwheels.Add(sir);
122 }
123 else
124 {
125 Plugin.slotSave.ActivatedWaterwheels.Remove(sir);
126 }
127 164
128 GameState.EvaluateGameStateListeners(listeners); 165 GameState.EvaluateGameStateListeners(listeners);
129 } 166 }
@@ -142,14 +179,7 @@ namespace ManifoldGardenArchipelago
142 return; 179 return;
143 } 180 }
144 181
145 if (newState == SphereController.State.AtDestination) 182 Plugin.slotSave.ActivatedSpheres[sir] = (newState == SphereController.State.AtDestination);
146 {
147 Plugin.slotSave.ActivatedSpheres.Add(sir);
148 }
149 else
150 {
151 Plugin.slotSave.ActivatedSpheres.Remove(sir);
152 }
153 183
154 GameState.EvaluateGameStateListeners(listeners); 184 GameState.EvaluateGameStateListeners(listeners);
155 } 185 }
@@ -166,10 +196,22 @@ namespace ManifoldGardenArchipelago
166 { 196 {
167 if (sceneDescription.doors.TryGetValue(sir.index, out var requirement)) 197 if (sceneDescription.doors.TryGetValue(sir.index, out var requirement))
168 { 198 {
169 FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic); 199 Requirement.Decision decision = requirement.Check();
170 fieldInfo.SetValue(__instance, requirement.Check()); 200
201 if (decision != Requirement.Decision.Maybe)
202 {
203 bool shouldOpen = (decision == Requirement.Decision.Yes);
204
205 FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic);
206 fieldInfo.SetValue(__instance, shouldOpen);
207
208 FieldInfo animatorInfo = typeof(LineDoorController).GetField("m_animator", BindingFlags.Instance | BindingFlags.NonPublic);
209 Animator animator = (Animator)animatorInfo.GetValue(__instance);
210
211 AnimatorExt.PlayDoorStateThenDisable(animator, __instance.DoorOpenAnimationString, shouldOpen ? 1f : -1f, true);
171 212
172 __instance.chains.Clear(); 213 __instance.chains.Clear();
214 }
173 } 215 }
174 } 216 }
175 } 217 }
@@ -180,16 +222,32 @@ namespace ManifoldGardenArchipelago
180 { 222 {
181 static void Prefix(LineDoorController __instance) 223 static void Prefix(LineDoorController __instance)
182 { 224 {
225 //Plugin.Logger.LogInfo("LineDoorControllerOnLoadPatch entered");
183 SceneItemReference sir = GameState.GetChainListenerSceneReference(__instance); 226 SceneItemReference sir = GameState.GetChainListenerSceneReference(__instance);
227 //Plugin.Logger.LogInfo($"Got sir {sir}");
184 228
185 if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription)) 229 if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription))
186 { 230 {
231 //Plugin.Logger.LogInfo($"{sceneDescription.doors.Count} doors in scene");
187 if (sceneDescription.doors.TryGetValue(sir.index, out var requirement)) 232 if (sceneDescription.doors.TryGetValue(sir.index, out var requirement))
188 { 233 {
189 FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic); 234 //Plugin.Logger.LogInfo($"Found req {requirement}");
190 fieldInfo.SetValue(__instance, requirement.Check()); 235 Requirement.Decision decision = requirement.Check();
236
237 if (decision != Requirement.Decision.Maybe)
238 {
239 bool shouldOpen = (decision == Requirement.Decision.Yes);
240
241 FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic);
242 fieldInfo.SetValue(__instance, shouldOpen);
243
244 FieldInfo animatorInfo = typeof(LineDoorController).GetField("m_animator", BindingFlags.Instance | BindingFlags.NonPublic);
245 Animator animator = (Animator)animatorInfo.GetValue(__instance);
246
247 AnimatorExt.PlayDoorStateThenDisable(animator, __instance.DoorOpenAnimationString, shouldOpen ? 1f : -1f, true);
191 248
192 __instance.chains.Clear(); 249 __instance.chains.Clear();
250 }
193 } 251 }
194 } 252 }
195 } 253 }
@@ -204,6 +262,7 @@ namespace ManifoldGardenArchipelago
204 262
205 if (GameData.listenersByScene.TryGetValue(newLevel.levelName, out var listeners)) 263 if (GameData.listenersByScene.TryGetValue(newLevel.levelName, out var listeners))
206 { 264 {
265 Plugin.Logger.LogInfo($"Evaluating for scene {newLevel.levelName}");
207 GameState.EvaluateGameStateListeners(listeners); 266 GameState.EvaluateGameStateListeners(listeners);
208 } 267 }
209 } 268 }
@@ -227,7 +286,7 @@ namespace ManifoldGardenArchipelago
227 286
228 if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription) && 287 if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription) &&
229 sceneDescription.worldGrows.TryGetValue(sir.index, out var requirement) && 288 sceneDescription.worldGrows.TryGetValue(sir.index, out var requirement) &&
230 requirement.Check()) 289 requirement.Check() == Requirement.Decision.Yes)
231 { 290 {
232 FieldInfo fieldInfo = typeof(DarkModeCollapsedCubeWorldGrow).GetField("m_grown", BindingFlags.Instance | BindingFlags.NonPublic); 291 FieldInfo fieldInfo = typeof(DarkModeCollapsedCubeWorldGrow).GetField("m_grown", BindingFlags.Instance | BindingFlags.NonPublic);
233 fieldInfo.SetValue(__instance, true); 292 fieldInfo.SetValue(__instance, true);
@@ -235,6 +294,54 @@ namespace ManifoldGardenArchipelago
235 } 294 }
236 } 295 }
237 296
297 [HarmonyPatch(typeof(SolidStateController), nameof(SolidStateController.OnChainFillComplete))]
298 static class SolidStateControllerOnChainFillCompletePatch
299 {
300 static bool Prefix(SolidStateController __instance)
301 {
302 SceneItemReference sir = GameState.GetChainListenerSceneReference(__instance);
303
304 if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription))
305 {
306 if (sceneDescription.smokeWalls.TryGetValue(sir.index, out var requirement))
307 {
308 Requirement.Decision decision = requirement.Check();
309
310 if (decision == Requirement.Decision.No)
311 {
312 return false;
313 }
314 }
315 }
316
317 return true;
318 }
319 }
320
321 [HarmonyPatch(typeof(SolidStateController), nameof(SolidStateController.OnUnfilled))]
322 static class SolidStateControllerOnUnfilledPatch
323 {
324 static bool Prefix(SolidStateController __instance)
325 {
326 SceneItemReference sir = GameState.GetChainListenerSceneReference(__instance);
327
328 if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription))
329 {
330 if (sceneDescription.smokeWalls.TryGetValue(sir.index, out var requirement))
331 {
332 Requirement.Decision decision = requirement.Check();
333
334 if (decision == Requirement.Decision.Yes)
335 {
336 return false;
337 }
338 }
339 }
340
341 return true;
342 }
343 }
344
238 [HarmonyPatch(typeof(DarkModeCollider), nameof(DarkModeCollider.OnLevelUpdate))] 345 [HarmonyPatch(typeof(DarkModeCollider), nameof(DarkModeCollider.OnLevelUpdate))]
239 static class DarkModeColliderOnLevelUpdatePatch 346 static class DarkModeColliderOnLevelUpdatePatch
240 { 347 {
diff --git a/Requirements.cs b/Requirements.cs index 987a299..81ecf36 100644 --- a/Requirements.cs +++ b/Requirements.cs
@@ -50,9 +50,16 @@ namespace ManifoldGardenArchipelago
50 50
51 public abstract class Requirement 51 public abstract class Requirement
52 { 52 {
53 public enum Decision
54 {
55 Maybe,
56 No,
57 Yes,
58 }
59
53 public RequirementReferences references = new(); 60 public RequirementReferences references = new();
54 61
55 public abstract bool Check(); 62 public abstract Decision Check();
56 } 63 }
57 64
58 public class AndRequirement : Requirement 65 public class AndRequirement : Requirement
@@ -69,9 +76,19 @@ namespace ManifoldGardenArchipelago
69 } 76 }
70 } 77 }
71 78
72 public override bool Check() 79 public override Decision Check()
73 { 80 {
74 return _requirements.All(x => x.Check()); 81 foreach (var requirement in _requirements)
82 {
83 Decision decision = requirement.Check();
84
85 if (decision != Decision.Yes)
86 {
87 return decision;
88 }
89 }
90
91 return Decision.Yes;
75 } 92 }
76 93
77 public override string ToString() 94 public override string ToString()
@@ -94,9 +111,19 @@ namespace ManifoldGardenArchipelago
94 } 111 }
95 } 112 }
96 113
97 public override bool Check() 114 public override Decision Check()
98 { 115 {
99 return _requirements.Any(x => x.Check()); 116 foreach (var requirement in _requirements)
117 {
118 Decision decision = requirement.Check();
119
120 if (decision != Decision.No)
121 {
122 return decision;
123 }
124 }
125
126 return Decision.No;
100 } 127 }
101 128
102 public override string ToString() 129 public override string ToString()
@@ -116,9 +143,9 @@ namespace ManifoldGardenArchipelago
116 references.items.Add(itemName); 143 references.items.Add(itemName);
117 } 144 }
118 145
119 public override bool Check() 146 public override Decision Check()
120 { 147 {
121 return Plugin.archipelagoManager.HasItem(_itemName); 148 return Plugin.archipelagoManager.HasItem(_itemName) ? Decision.Yes : Decision.No;
122 } 149 }
123 150
124 public override string ToString() 151 public override string ToString()
@@ -138,9 +165,9 @@ namespace ManifoldGardenArchipelago
138 references.scenes.Add(sceneName); 165 references.scenes.Add(sceneName);
139 } 166 }
140 167
141 public override bool Check() 168 public override Decision Check()
142 { 169 {
143 return Plugin.slotSave.VisitedScenes.Contains(_sceneName); 170 return Plugin.slotSave.VisitedScenes.Contains(_sceneName) ? Decision.Yes : Decision.No;
144 } 171 }
145 172
146 public override string ToString() 173 public override string ToString()
@@ -161,9 +188,16 @@ namespace ManifoldGardenArchipelago
161 references.buttons.Add(button); 188 references.buttons.Add(button);
162 } 189 }
163 190
164 public override bool Check() 191 public override Decision Check()
165 { 192 {
166 return Plugin.slotSave.ActivatedButtons.Contains(_button); 193 if (Plugin.slotSave.ActivatedButtons.TryGetValue(_button, out bool value))
194 {
195 return value ? Decision.Yes : Decision.No;
196 }
197 else
198 {
199 return Decision.Maybe;
200 }
167 } 201 }
168 202
169 public override string ToString() 203 public override string ToString()
@@ -184,9 +218,16 @@ namespace ManifoldGardenArchipelago
184 references.sockets.Add(socket); 218 references.sockets.Add(socket);
185 } 219 }
186 220
187 public override bool Check() 221 public override Decision Check()
188 { 222 {
189 return Plugin.slotSave.ActivatedSockets.Contains(_socket); 223 if (Plugin.slotSave.ActivatedSockets.TryGetValue(_socket, out bool value))
224 {
225 return value ? Decision.Yes : Decision.No;
226 }
227 else
228 {
229 return Decision.Maybe;
230 }
190 } 231 }
191 232
192 public override string ToString() 233 public override string ToString()
@@ -207,9 +248,16 @@ namespace ManifoldGardenArchipelago
207 references.pads.Add(pad); 248 references.pads.Add(pad);
208 } 249 }
209 250
210 public override bool Check() 251 public override Decision Check()
211 { 252 {
212 return Plugin.slotSave.ActivatedPads.Contains(_pad); 253 if (Plugin.slotSave.ActivatedPads.TryGetValue(_pad, out bool value))
254 {
255 return value ? Decision.Yes : Decision.No;
256 }
257 else
258 {
259 return Decision.Maybe;
260 }
213 } 261 }
214 262
215 public override string ToString() 263 public override string ToString()
@@ -230,9 +278,16 @@ namespace ManifoldGardenArchipelago
230 references.waterwheels.Add(waterwheel); 278 references.waterwheels.Add(waterwheel);
231 } 279 }
232 280
233 public override bool Check() 281 public override Decision Check()
234 { 282 {
235 return Plugin.slotSave.ActivatedWaterwheels.Contains(_waterwheel); 283 if (Plugin.slotSave.ActivatedWaterwheels.TryGetValue(_waterwheel, out bool value))
284 {
285 return value ? Decision.Yes : Decision.No;
286 }
287 else
288 {
289 return Decision.Maybe;
290 }
236 } 291 }
237 292
238 public override string ToString() 293 public override string ToString()
@@ -253,9 +308,16 @@ namespace ManifoldGardenArchipelago
253 references.spheres.Add(sphere); 308 references.spheres.Add(sphere);
254 } 309 }
255 310
256 public override bool Check() 311 public override Decision Check()
257 { 312 {
258 return Plugin.slotSave.ActivatedSpheres.Contains(_sphere); 313 if (Plugin.slotSave.ActivatedSpheres.TryGetValue(_sphere, out bool value))
314 {
315 return value ? Decision.Yes : Decision.No;
316 }
317 else
318 {
319 return Decision.Maybe;
320 }
259 } 321 }
260 322
261 public override string ToString() 323 public override string ToString()
@@ -275,9 +337,22 @@ namespace ManifoldGardenArchipelago
275 references = requirement.references; 337 references = requirement.references;
276 } 338 }
277 339
278 public override bool Check() 340 public override Decision Check()
279 { 341 {
280 return !_requirement.Check(); 342 Decision subdec = _requirement.Check();
343
344 if (subdec == Decision.Yes)
345 {
346 return Decision.No;
347 }
348 else if (subdec == Decision.No)
349 {
350 return Decision.Yes;
351 }
352 else
353 {
354 return Decision.Maybe;
355 }
281 } 356 }
282 357
283 public override string ToString() 358 public override string ToString()
diff --git a/SlotSave.cs b/SlotSave.cs index 6261890..dfa18bc 100644 --- a/SlotSave.cs +++ b/SlotSave.cs
@@ -1,18 +1,14 @@
1using System; 1using System.Collections.Generic;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Threading.Tasks;
6 2
7namespace ManifoldGardenArchipelago 3namespace ManifoldGardenArchipelago
8{ 4{
9 public class SlotSave 5 public class SlotSave
10 { 6 {
11 public readonly HashSet<string> VisitedScenes = []; 7 public readonly HashSet<string> VisitedScenes = [];
12 public readonly HashSet<SceneItemReference> ActivatedButtons = []; 8 public readonly Dictionary<SceneItemReference, bool> ActivatedButtons = [];
13 public readonly HashSet<SceneItemReference> ActivatedSockets = []; 9 public readonly Dictionary<SceneItemReference, bool> ActivatedSockets = [];
14 public readonly HashSet<SceneItemReference> ActivatedPads = []; 10 public readonly Dictionary<SceneItemReference, bool> ActivatedPads = [];
15 public readonly HashSet<SceneItemReference> ActivatedWaterwheels = []; 11 public readonly Dictionary<SceneItemReference, bool> ActivatedWaterwheels = [];
16 public readonly HashSet<SceneItemReference> ActivatedSpheres = []; 12 public readonly Dictionary<SceneItemReference, bool> ActivatedSpheres = [];
17 } 13 }
18} 14}
diff --git a/game_data.yaml b/game_data.yaml index 43ccf22..a261be0 100644 --- a/game_data.yaml +++ b/game_data.yaml
@@ -274,24 +274,25 @@ World_612_BlindSpherePuzzle_Optimized:
274 scene: Hallway_W612_W057_Optimized 274 scene: Hallway_W612_W057_Optimized
275 index: 0 275 index: 0
276World_018_PastaTile_Optimized: 276World_018_PastaTile_Optimized:
277 0: 277 doors:
278 or: 278 0:
279 - button: 0 279 or:
280 - pad: 0 280 - button: 0
281 3: 281 - pad: 0
282 or: 282 3:
283 - pad: 0 283 or:
284 - sphere: 284 - pad: 0
285 scene: Hallway_W018_W003B_Optimized 285 - sphere:
286 index: 0 286 scene: Hallway_W018_W003B_Optimized
287 5: 287 index: 0
288 or: 288 5:
289 - button: 1 289 or:
290 - button: 290 - button: 1
291 - scene: Hallway_W018_W063_Optimized 291 - button:
292 index: 0 292 - scene: Hallway_W018_W063_Optimized
293 - scene: Hallway_W018_W063_Optimized 293 index: 0
294 index: 1 294 - scene: Hallway_W018_W063_Optimized
295 index: 1
295Hallway_W018_W003B_Optimized: 296Hallway_W018_W003B_Optimized:
296 locations: 297 locations:
297 Mini Sphere Puzzle Solved: 298 Mini Sphere Puzzle Solved:
@@ -559,6 +560,7 @@ World_026_Library_Optimized:
559 smoke: 560 smoke:
560 3: 561 3:
561 item: Library - Yellow Smoke Wall 562 item: Library - Yellow Smoke Wall
563 entry: World_026_Library_Optimized
562Hallway_W026_W002_Optimized: 564Hallway_W026_W002_Optimized:
563 locations: 565 locations:
564 Yellow Cube Fetch Quest Completed: 566 Yellow Cube Fetch Quest Completed: