using NewHorizons.Builder.General; using NewHorizons.Builder.Orbital; using NewHorizons.Components.Orbital; using NewHorizons.External.Modules; using NewHorizons.Handlers; using NewHorizons.Utility; using System.Collections.Generic; using UnityEngine; using Logger = NewHorizons.Utility.Logger; using Random = UnityEngine.Random; namespace NewHorizons.Components { public class QuantumPlanet : QuantumObject { public List states = new List(); public State groundState; private int _currentIndex; private NHAstroObject _astroObject; private ConstantForceDetector _detector; private AlignWithTargetBody _alignment; private OWRigidbody _rb; public override void Awake() { base.Awake(); _astroObject = GetComponent(); _detector = GetComponentInChildren(); _alignment = GetComponent(); _rb = GetComponent(); GlobalMessenger.AddListener("PlayerBlink", new Callback(OnPlayerBlink)); _maxSnapshotLockRange = 300000f; } public override void Start() { base.Start(); foreach (var state in states) { state.sector?.gameObject?.SetActive(false); } ChangeQuantumState(true); } public override bool ChangeQuantumState(bool skipInstantVisibilityCheck) { Logger.Log($"Trying to change quantum state"); if (states.Count <= 1) return false; // Don't move if we have a picture or if we're on it if (IsLockedByProbeSnapshot() || IsPlayerEntangled()) return false; var canChange = false; var oldState = states[_currentIndex]; // This will all get set in the for loop State newState = oldState; int newIndex = _currentIndex; AstroObject primaryBody = null; OrbitalParameters orbitalParams = null; // The QM tries to switch 10 times so we'll do that too for (int i = 0; i < 10; i++) { newIndex = _currentIndex; while (newIndex == _currentIndex) { newIndex = Random.Range(0, states.Count); } newState = states[newIndex]; // Figure out what the new orbit will be if we switch var newOrbit = newState.orbit ?? groundState.orbit; newOrbit.TrueAnomaly = Random.Range(0f, 360f); primaryBody = AstroObjectLocator.GetAstroObject(newOrbit.PrimaryBody); var primaryGravity = new Gravity(primaryBody.GetGravityVolume()); var secondaryGravity = new Gravity(_astroObject.GetGravityVolume()); orbitalParams = newOrbit.GetOrbitalParameters(primaryGravity, secondaryGravity); var pos = primaryBody.transform.position + orbitalParams.InitialPosition; // See if we can switch, so we move the visibility tracker to the new position _visibilityTrackers[0].transform.position = pos; // Only if not seen if (!CheckVisibilityInstantly()) { canChange = true; // Since we were able to change states we break break; } } if (canChange) { if (newState.sector != null && newState.sector != oldState.sector) SetNewSector(oldState, newState); if (newState.orbit != null && newState.orbit != oldState.orbit) SetNewOrbit(primaryBody, orbitalParams); _currentIndex = newIndex; } // Be completely sure we move the visibility tracker back to our planet _visibilityTrackers[0].transform.localPosition = Vector3.zero; return true; } private void SetNewSector(State oldState, State newState) { oldState.sector.gameObject.SetActive(false); newState.sector.gameObject.SetActive(true); } private void SetNewOrbit(AstroObject primaryBody, OrbitalParameters orbitalParameters) { _astroObject._primaryBody = primaryBody; DetectorBuilder.SetDetector(primaryBody, _astroObject, _detector); _detector._activeInheritedDetector = primaryBody.GetComponentInChildren(); _detector._activeVolumes = new List() { primaryBody.GetGravityVolume() }; if (_alignment != null) _alignment.SetTargetBody(primaryBody.GetComponent()); _astroObject.SetOrbitalParametersFromTrueAnomaly(orbitalParameters.Eccentricity, orbitalParameters.SemiMajorAxis, orbitalParameters.Inclination, orbitalParameters.ArgumentOfPeriapsis, orbitalParameters.LongitudeOfAscendingNode, orbitalParameters.TrueAnomaly); PlanetCreationHandler.UpdatePosition(gameObject, orbitalParameters, primaryBody, _astroObject); if (!Physics.autoSyncTransforms) { Physics.SyncTransforms(); } _rb.SetVelocity(orbitalParameters.InitialVelocity + primaryBody.GetAttachedOWRigidbody().GetVelocity()); } private void OnPlayerBlink() { if (base.IsVisible()) { base.Collapse(true); } } public override bool IsPlayerEntangled() { return states[_currentIndex].sector.ContainsAnyOccupants(DynamicOccupant.Player); } public class State { public Sector sector { get; set; } public OrbitModule orbit { get; set; } public State(Sector sector, OrbitModule orbit) { this.sector = sector; this.orbit = orbit; } } } }