diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2025-02-23 16:42:22 -0500 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2025-02-23 16:42:22 -0500 |
commit | 42bc500a77f4b29d952058aede6abfaf91bd74c8 (patch) | |
tree | bfcdf83f9ec863f807fc9df48c0326ba56402a8e | |
parent | f5b0daa0279ce4ed272b007ac4324e848ad4b03d (diff) | |
download | manifold-garden-archipelago-42bc500a77f4b29d952058aede6abfaf91bd74c8.tar.gz manifold-garden-archipelago-42bc500a77f4b29d952058aede6abfaf91bd74c8.tar.bz2 manifold-garden-archipelago-42bc500a77f4b29d952058aede6abfaf91bd74c8.zip |
Add support for lasers
The three lasers in Blue are item locked, and the laser in Akshardham requires you to have planted all other god cubes in order to activate.
-rw-r--r-- | ArchipelagoManager.cs | 1 | ||||
-rw-r--r-- | GameData.cs | 51 | ||||
-rw-r--r-- | GameState.cs | 46 | ||||
-rw-r--r-- | GameplayPatches.cs | 48 | ||||
-rw-r--r-- | game_data.yaml | 31 |
5 files changed, 175 insertions, 2 deletions
diff --git a/ArchipelagoManager.cs b/ArchipelagoManager.cs index 998e2d9..5e1d867 100644 --- a/ArchipelagoManager.cs +++ b/ArchipelagoManager.cs | |||
@@ -29,6 +29,7 @@ namespace ManifoldGardenArchipelago | |||
29 | } | 29 | } |
30 | catch (Exception ex) | 30 | catch (Exception ex) |
31 | { | 31 | { |
32 | Plugin.Logger.LogError(ex.GetBaseException().Message); | ||
32 | return new LoginFailure(ex.GetBaseException().Message); | 33 | return new LoginFailure(ex.GetBaseException().Message); |
33 | } | 34 | } |
34 | 35 | ||
diff --git a/GameData.cs b/GameData.cs index 6b5eddc..f8adb17 100644 --- a/GameData.cs +++ b/GameData.cs | |||
@@ -27,6 +27,7 @@ namespace ManifoldGardenArchipelago | |||
27 | public readonly Dictionary<int, Requirement> doors = []; | 27 | public readonly Dictionary<int, Requirement> doors = []; |
28 | public readonly Dictionary<int, Requirement> smokeWalls = []; | 28 | public readonly Dictionary<int, Requirement> smokeWalls = []; |
29 | public readonly Dictionary<int, Requirement> worldGrows = []; | 29 | public readonly Dictionary<int, Requirement> worldGrows = []; |
30 | public readonly Dictionary<int, Requirement> lasers = []; | ||
30 | } | 31 | } |
31 | 32 | ||
32 | public class GameStateListeners | 33 | public class GameStateListeners |
@@ -35,6 +36,7 @@ namespace ManifoldGardenArchipelago | |||
35 | public readonly Dictionary<SceneItemReference, Requirement> doors = []; | 36 | public readonly Dictionary<SceneItemReference, Requirement> doors = []; |
36 | public readonly Dictionary<SceneItemReference, Requirement> smokeWalls = []; | 37 | public readonly Dictionary<SceneItemReference, Requirement> smokeWalls = []; |
37 | public readonly Dictionary<SceneItemReference, Requirement> worldGrows = []; | 38 | public readonly Dictionary<SceneItemReference, Requirement> worldGrows = []; |
39 | public readonly Dictionary<SceneItemReference, Requirement> lasers = []; | ||
38 | } | 40 | } |
39 | 41 | ||
40 | public static class GameData | 42 | public static class GameData |
@@ -419,6 +421,8 @@ namespace ManifoldGardenArchipelago | |||
419 | Requirement req = ParseRequirement(scenePair.Key, (Dictionary<object, object>)worldPair.Value); | 421 | Requirement req = ParseRequirement(scenePair.Key, (Dictionary<object, object>)worldPair.Value); |
420 | sceneDescription.worldGrows[sir.index] = req; | 422 | sceneDescription.worldGrows[sir.index] = req; |
421 | 423 | ||
424 | Plugin.Logger.LogInfo($"World {sir} requirements: {req}"); | ||
425 | |||
422 | foreach (var reqScene in req.references.scenes) | 426 | foreach (var reqScene in req.references.scenes) |
423 | { | 427 | { |
424 | GetOrAddListeners(listenersByScene, reqScene).worldGrows[sir] = req; | 428 | GetOrAddListeners(listenersByScene, reqScene).worldGrows[sir] = req; |
@@ -456,6 +460,53 @@ namespace ManifoldGardenArchipelago | |||
456 | } | 460 | } |
457 | } | 461 | } |
458 | 462 | ||
463 | if (sceneDetails.ContainsKey("lasers")) | ||
464 | { | ||
465 | foreach (var laserPair in (Dictionary<object, object>)sceneDetails["lasers"]) | ||
466 | { | ||
467 | SceneItemReference sir = new(scenePair.Key, int.Parse((string)laserPair.Key)); | ||
468 | Requirement req = ParseRequirement(scenePair.Key, (Dictionary<object, object>)laserPair.Value); | ||
469 | sceneDescription.lasers[sir.index] = req; | ||
470 | |||
471 | Plugin.Logger.LogInfo($"Laser {sir} requirements: {req}"); | ||
472 | |||
473 | foreach (var reqScene in req.references.scenes) | ||
474 | { | ||
475 | GetOrAddListeners(listenersByScene, reqScene).lasers[sir] = req; | ||
476 | } | ||
477 | |||
478 | foreach (var button in req.references.buttons) | ||
479 | { | ||
480 | GetOrAddListeners(listenersByButton, button).lasers[sir] = req; | ||
481 | } | ||
482 | |||
483 | foreach (var socket in req.references.sockets) | ||
484 | { | ||
485 | GetOrAddListeners(listenersBySocket, socket).lasers[sir] = req; | ||
486 | } | ||
487 | |||
488 | foreach (var pad in req.references.pads) | ||
489 | { | ||
490 | GetOrAddListeners(listenersByPad, pad).lasers[sir] = req; | ||
491 | } | ||
492 | |||
493 | foreach (var waterwheel in req.references.waterwheels) | ||
494 | { | ||
495 | GetOrAddListeners(listenersByWaterwheel, waterwheel).lasers[sir] = req; | ||
496 | } | ||
497 | |||
498 | foreach (var sphere in req.references.spheres) | ||
499 | { | ||
500 | GetOrAddListeners(listenersBySphere, sphere).lasers[sir] = req; | ||
501 | } | ||
502 | |||
503 | foreach (var item in req.references.items) | ||
504 | { | ||
505 | GetOrAddListeners(listenersByItem, item).lasers[sir] = req; | ||
506 | } | ||
507 | } | ||
508 | } | ||
509 | |||
459 | scenes[scenePair.Key] = sceneDescription; | 510 | scenes[scenePair.Key] = sceneDescription; |
460 | } | 511 | } |
461 | } | 512 | } |
diff --git a/GameState.cs b/GameState.cs index bdf5760..9280eb3 100644 --- a/GameState.cs +++ b/GameState.cs | |||
@@ -33,6 +33,21 @@ namespace ManifoldGardenArchipelago | |||
33 | throw new Exception("Shouldn't happen"); | 33 | throw new Exception("Shouldn't happen"); |
34 | } | 34 | } |
35 | 35 | ||
36 | public static SceneItemReference GetGameplayComponentSceneReference(Component component) | ||
37 | { | ||
38 | LevelSystems levelSystem = GetLevelSystems(component); | ||
39 | |||
40 | for (int i = 0; i < levelSystem.gameplayComponentsInLevel.Count(); i++) | ||
41 | { | ||
42 | if (levelSystem.gameplayComponentsInLevel[i] == component) | ||
43 | { | ||
44 | return new(component.gameObject.scene.name, i); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | throw new Exception("Shouldn't happen"); | ||
49 | } | ||
50 | |||
36 | public static SceneItemReference GetButtonSceneReference(ButtonLineActivator arg) | 51 | public static SceneItemReference GetButtonSceneReference(ButtonLineActivator arg) |
37 | { | 52 | { |
38 | LevelSystems levelSystem = GetLevelSystems(arg); | 53 | LevelSystems levelSystem = GetLevelSystems(arg); |
@@ -191,6 +206,37 @@ namespace ManifoldGardenArchipelago | |||
191 | } | 206 | } |
192 | } | 207 | } |
193 | } | 208 | } |
209 | |||
210 | foreach (var laser in listeners.lasers) | ||
211 | { | ||
212 | Requirement.Decision decision = laser.Value.Check(); | ||
213 | if (decision == Requirement.Decision.Maybe) | ||
214 | { | ||
215 | continue; | ||
216 | } | ||
217 | |||
218 | bool shouldOpen = (decision == Requirement.Decision.Yes); | ||
219 | |||
220 | if (SceneManager.GetSceneByName(laser.Key.scene) is Scene laserScene && laserScene.isLoaded) | ||
221 | { | ||
222 | LevelSystems levelSystems = GetLevelSystems(laserScene); | ||
223 | if (levelSystems.isActiveAndEnabled) | ||
224 | { | ||
225 | DarkModeCageController ldc = levelSystems.gameplayComponentsInLevel[laser.Key.index].GetComponent<DarkModeCageController>(); | ||
226 | |||
227 | if (shouldOpen) | ||
228 | { | ||
229 | MethodInfo methodInfo = typeof(DarkModeCageController).GetMethod("OpenLaserSource", BindingFlags.Instance | BindingFlags.NonPublic); | ||
230 | methodInfo.Invoke(ldc, [false]); | ||
231 | } | ||
232 | else | ||
233 | { | ||
234 | MethodInfo methodInfo = typeof(DarkModeCageController).GetMethod("CloseLaserSource", BindingFlags.Instance | BindingFlags.NonPublic); | ||
235 | methodInfo.Invoke(ldc, [false]); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | } | ||
194 | } | 240 | } |
195 | } | 241 | } |
196 | } | 242 | } |
diff --git a/GameplayPatches.cs b/GameplayPatches.cs index bdcbcae..37a671d 100644 --- a/GameplayPatches.cs +++ b/GameplayPatches.cs | |||
@@ -389,4 +389,52 @@ namespace ManifoldGardenArchipelago | |||
389 | return false; | 389 | return false; |
390 | } | 390 | } |
391 | } | 391 | } |
392 | |||
393 | [HarmonyPatch(typeof(DarkModeCageController), "StartFilling")] | ||
394 | static class DarkModeCageControllerStartFillingPatch | ||
395 | { | ||
396 | static bool Prefix(DarkModeCageController __instance) | ||
397 | { | ||
398 | SceneItemReference sir = GameState.GetGameplayComponentSceneReference(__instance); | ||
399 | |||
400 | if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription)) | ||
401 | { | ||
402 | if (sceneDescription.lasers.TryGetValue(sir.index, out var requirement)) | ||
403 | { | ||
404 | Requirement.Decision decision = requirement.Check(); | ||
405 | |||
406 | if (decision == Requirement.Decision.No) | ||
407 | { | ||
408 | return false; | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | |||
413 | return true; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | [HarmonyPatch(typeof(DarkModeCageController), "StartUnfilling")] | ||
418 | static class DarkModeCageControllerStartUnfillingPatch | ||
419 | { | ||
420 | static bool Prefix(DarkModeCageController __instance) | ||
421 | { | ||
422 | SceneItemReference sir = GameState.GetGameplayComponentSceneReference(__instance); | ||
423 | |||
424 | if (GameData.scenes.TryGetValue(sir.scene, out var sceneDescription)) | ||
425 | { | ||
426 | if (sceneDescription.lasers.TryGetValue(sir.index, out var requirement)) | ||
427 | { | ||
428 | Requirement.Decision decision = requirement.Check(); | ||
429 | |||
430 | if (decision == Requirement.Decision.Yes) | ||
431 | { | ||
432 | return false; | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | |||
437 | return true; | ||
438 | } | ||
439 | } | ||
392 | } | 440 | } |
diff --git a/game_data.yaml b/game_data.yaml index 891b169..fe5d99a 100644 --- a/game_data.yaml +++ b/game_data.yaml | |||
@@ -75,7 +75,6 @@ Hallway_W062_W063_Optimized: | |||
75 | scene: World_063_TowerX_Optimized | 75 | scene: World_063_TowerX_Optimized |
76 | index: 0 | 76 | index: 0 |
77 | World_001_Optimized: | 77 | World_001_Optimized: |
78 | # lasers are called DarkModeCageControllers; will handle them separately bc most worlds don't item-lock them | ||
79 | locations: | 78 | locations: |
80 | Blue - Red Laser Activated: | 79 | Blue - Red Laser Activated: |
81 | socket: 5 | 80 | socket: 5 |
@@ -85,6 +84,17 @@ World_001_Optimized: | |||
85 | socket: 3 | 84 | socket: 3 |
86 | Blue - Tree Purified: | 85 | Blue - Tree Purified: |
87 | entry: AudioVisual_001_Optimized | 86 | entry: AudioVisual_001_Optimized |
87 | lasers: | ||
88 | # These are gameplayComponentsInLevel indicies | ||
89 | 127: | ||
90 | item: Blue - Green Laser | ||
91 | socket: 3 | ||
92 | 133: | ||
93 | item: Blue - Yellow Laser | ||
94 | socket: 4 | ||
95 | 149: | ||
96 | item: Blue - Red Laser | ||
97 | socket: 5 | ||
88 | World_044_CubicSpaceDivision_Optimized: | 98 | World_044_CubicSpaceDivision_Optimized: |
89 | locations: | 99 | locations: |
90 | Blue God Cube Planted: | 100 | Blue God Cube Planted: |
@@ -437,7 +447,7 @@ Hallway_W073_W018_Optimized: | |||
437 | Hallway_W018_W063_Optimized: | 447 | Hallway_W018_W063_Optimized: |
438 | doors: | 448 | doors: |
439 | 0: | 449 | 0: |
440 | - button: [0, 1] | 450 | button: [0, 1] |
441 | 1: | 451 | 1: |
442 | item: Orange Secret Path | 452 | item: Orange Secret Path |
443 | or: | 453 | or: |
@@ -758,3 +768,20 @@ World_806_Optimized: | |||
758 | locations: | 768 | locations: |
759 | Rainbow - Second Water Tetromino Puzzle Solved: | 769 | Rainbow - Second Water Tetromino Puzzle Solved: |
760 | waterwheel: 0 | 770 | waterwheel: 0 |
771 | World_071_AkshardhamTemple_Optimized: | ||
772 | lasers: | ||
773 | 49: | ||
774 | waterwheel: 0 | ||
775 | socket: | ||
776 | - scene: World_044_CubicSpaceDivision_Optimized | ||
777 | index: 0 | ||
778 | - scene: World_044_CubicSpaceDivision_Optimized | ||
779 | index: 1 | ||
780 | - scene: World_044_CubicSpaceDivision_Optimized | ||
781 | index: 2 | ||
782 | - scene: World_044_CubicSpaceDivision_Optimized | ||
783 | index: 3 | ||
784 | - scene: World_044_CubicSpaceDivision_Optimized | ||
785 | index: 4 | ||
786 | - scene: World_044_CubicSpaceDivision_Optimized | ||
787 | index: 5 | ||