From 20d524d3defba3233e999361e3bae13d053db53d Mon Sep 17 00:00:00 2001 From: xen-42 Date: Mon, 6 Jan 2025 17:51:09 -0500 Subject: [PATCH] Port over quantum stuff from escape room --- NewHorizons/Builder/Props/QuantumBuilder.cs | 46 +++++++++++++-- .../SnapshotLockableVisiblityObject.cs | 57 +++++++++++++++++++ NewHorizons/External/Configs/PlanetConfig.cs | 2 +- 3 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 NewHorizons/Components/Quantum/SnapshotLockableVisiblityObject.cs diff --git a/NewHorizons/Builder/Props/QuantumBuilder.cs b/NewHorizons/Builder/Props/QuantumBuilder.cs index 61d631b2..aa4e9461 100644 --- a/NewHorizons/Builder/Props/QuantumBuilder.cs +++ b/NewHorizons/Builder/Props/QuantumBuilder.cs @@ -1,9 +1,8 @@ using NewHorizons.Components.Quantum; -using NewHorizons.External.Configs; +using NewHorizons.External.Modules.Props; using NewHorizons.External.Modules.Props.Quantum; using NewHorizons.Utility.Geometry; using NewHorizons.Utility.OWML; -using OWML.Common; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -27,7 +26,7 @@ namespace NewHorizons.Builder.Props /* public static void MakeQuantumLightning(GameObject planetGO, Sector sector, GameObject[] propsInGroup) { - var lightning = DetailBuilder.Make(planetGO, sector, AssetBundleUtilities.EyeLightning.LoadAsset("Prefab_EYE_QuantumLightningObject"), new DetailInfo()); + var lightning = DetailBuilder.Make(planetGO, sector, Main.Instance, AssetBundleUtilities.EyeLightning.LoadAsset("Prefab_EYE_QuantumLightningObject"), new DetailInfo()); lightning.transform.position = prop.transform.position; lightning.transform.rotation = prop.transform.rotation; lightning.transform.parent = prop.transform.parent; @@ -45,6 +44,16 @@ namespace NewHorizons.Builder.Props // Nice to have: socket groups that specify a filledSocketObject and an emptySocketObject (eg the archway in the giant's deep tower) public static void MakeSocketGroup(GameObject planetGO, Sector sector, SocketQuantumGroupInfo quantumGroup, GameObject[] propsInGroup) { + GameObject specialProp = null; + if (propsInGroup.Length == quantumGroup.sockets.Length) + { + // Special case! + specialProp = propsInGroup.Last(); + var propsInGroupList = propsInGroup.ToList(); + propsInGroupList.RemoveAt(propsInGroup.Length - 1); + propsInGroup = propsInGroupList.ToArray(); + } + var groupRoot = new GameObject("Quantum Sockets - " + quantumGroup.id); groupRoot.transform.parent = sector?.transform ?? planetGO.transform; groupRoot.transform.localPosition = Vector3.zero; @@ -77,11 +86,38 @@ namespace NewHorizons.Builder.Props { BoundsUtilities.AddBoundsVisibility(prop); } - prop.SetActive(true); } + if (specialProp != null) + { + // Can't have 4 objects in 4 slots + // Instead we have a duplicate of the final object for each slot, which appears when that slot is "empty" + for (int i = 0; i < sockets.Length; i++) + { + var emptySocketObject = DetailBuilder.Make(planetGO, sector, Main.Instance, specialProp, new DetailInfo()); + var socket = sockets[i]; + socket._emptySocketObject = emptySocketObject; + emptySocketObject.SetActive(socket._quantumObject == null); + emptySocketObject.transform.parent = socket.transform; + emptySocketObject.transform.localPosition = Vector3.zero; + emptySocketObject.transform.localRotation = Quaternion.identity; + // Need to add a visibility tracker for this socket else it doesn't stay "empty" when photographed + socket.SetActive(false); + var tracker = new GameObject("VisibilityTracker"); + tracker.transform.parent = socket.transform; + tracker.transform.localPosition = Vector3.zero; + tracker.transform.localRotation = Quaternion.identity; + var box = tracker.AddComponent(); + box.size = new Vector3(0.2f, 0.6f, 0.2f); + box.center = new Vector3(0, 0.3f, 0); + tracker.AddComponent(); + // Using a quantum object bc it can be locked by camera + socket._visibilityObject = socket.gameObject.AddComponent(); + socket.SetActive(true); + } + } } public static void MakeStateGroup(GameObject go, Sector sector, StateQuantumGroupInfo quantumGroup, GameObject[] propsInGroup) @@ -138,7 +174,7 @@ namespace NewHorizons.Builder.Props groupRoot.SetActive(true); } - public static void MakeShuffleGroup(GameObject go, Sector sector, QuantumGroupInfo quantumGroup, GameObject[] propsInGroup) + public static void MakeShuffleGroup(GameObject go, Sector sector, BaseQuantumGroupInfo quantumGroup, GameObject[] propsInGroup) { //var averagePosition = propsInGroup.Aggregate(Vector3.zero, (avg, prop) => avg + prop.transform.position) / propsInGroup.Count(); GameObject shuffleParent = new GameObject("Quantum Shuffle - " + quantumGroup.id); diff --git a/NewHorizons/Components/Quantum/SnapshotLockableVisiblityObject.cs b/NewHorizons/Components/Quantum/SnapshotLockableVisiblityObject.cs new file mode 100644 index 00000000..4fb52a4c --- /dev/null +++ b/NewHorizons/Components/Quantum/SnapshotLockableVisiblityObject.cs @@ -0,0 +1,57 @@ +using HarmonyLib; +using System.Linq; + +namespace NewHorizons.Components.Quantum; + +/// +/// A quantum object that does nothing but track if its been photographed +/// +internal class SnapshotLockableVisibilityObject : QuantumObject +{ + public override bool ChangeQuantumState(bool skipInstantVisibilityCheck) => true; +} + + +[HarmonyPatch(typeof(SocketedQuantumObject))] +public static class SocketedQuantumObjectPatches +{ + private static bool _skipPatch; + [HarmonyPrefix] + [HarmonyPatch(typeof(SocketedQuantumObject), nameof(SocketedQuantumObject.MoveToSocket))] + private static bool SocketedQuantumObject_MoveToSocket(SocketedQuantumObject __instance, QuantumSocket socket) + { + if (_skipPatch) + { + return true; + } + + if (socket.GetVisibilityObject() is SnapshotLockableVisibilityObject qObj) + { + // Do not allow it to switch to a socket that is photographed + // Instead try to swap with an occupied socket + if (qObj.IsLockedByProbeSnapshot()) + { + _skipPatch = true; + // Try to swap + var swapSocket = __instance._socketList.FirstOrDefault(x => x._quantumObject != null && x._quantumObject != __instance && !x._quantumObject.IsLocked()); + if (swapSocket != null) + { + var originalSocket = __instance.GetCurrentSocket(); + var otherQObj = swapSocket._quantumObject as SocketedQuantumObject; + otherQObj.MoveToSocket(socket); + __instance.MoveToSocket(swapSocket); + otherQObj.MoveToSocket(originalSocket); + } + else + { + __instance.MoveToSocket(__instance.GetCurrentSocket()); + } + + _skipPatch = false; + return false; + } + } + + return true; + } +} diff --git a/NewHorizons/External/Configs/PlanetConfig.cs b/NewHorizons/External/Configs/PlanetConfig.cs index 80407c89..c9364aeb 100644 --- a/NewHorizons/External/Configs/PlanetConfig.cs +++ b/NewHorizons/External/Configs/PlanetConfig.cs @@ -707,7 +707,7 @@ namespace NewHorizons.External.Configs } } - if (Props != null) + if (Props != null && Props.quantumGroups != null) { var socketQuantumGroups = Props.quantumGroups.Where(x => x.type == QuantumGroupType.Sockets).Select(x => new SocketQuantumGroupInfo() {