using System; using System.Collections.Generic; using System.IO; using UnityEngine; /// <summary> /// Handles weather generation in an Encounter /// </summary> public class ClimateManager : MonoBehaviour { public enum Weather { Sunny, Cloudy, Rainy, Monsoon, Snowy, Blizzard, Foggy, Eclipsed } public enum Locations { Swamplands, DarkVillage, AbandonedManor, FrozenWasteland, Village } public static ClimateManager Instance { get; private set; } [Header("Weather Aspects")] [SerializeField] private Transform effectObjectTransform; // Game Object that holds the particle effects for the Encounter [SerializeField] private List<GameObject> sunnyEffects; [SerializeField] private List<GameObject> clearNightEffects; [SerializeField] private List<GameObject> cloudyEffects; [SerializeField] private List<GameObject> rainyEffects; [SerializeField] private List<GameObject> monsoonEffects; [SerializeField] private List<GameObject> snowyEffects; [SerializeField] private List<GameObject> blizzardEffects; [SerializeField] private List<GameObject> foggyEffects; [SerializeField] private List<GameObject> eclipseEffects; [Header("Location Aspects")] [SerializeField] private Transform spriteGridTransform; [SerializeField] private List<GameObject> swamplandSprites; [SerializeField] private List<GameObject> frozenWastelandSprites; [SerializeField] private List<GameObject> darkVillageSprites; [SerializeField] private List<GameObject> abandonedManorSprites; [SerializeField] private List<GameObject> villageSprites; private const int WeatherTypeCount = 7; // Liable to change private readonly Color DayTime = new Color(.39f, .35f, .26f, 1f); // Day time camera background color private readonly Color NightTime = new Color(.17f, .17f, .17f, 1f); // Night time camera background color private int currentEncounterValue; // Reference to the encounter value of the current game state private Weather currentWeather; // Current Weather of Encounter private Locations currentLocation; // Current Location of Encounter private bool IsDayTime; // Switch indicator for if it is currently day time or night time private void Awake() { Instance = this; // Set as false and will be switched to true for the first encounter IsDayTime = false; } /// <summary> /// Sets the current weather of the Encounter /// </summary> private void SetWeather() { // Clears all of the particle systems for the current weather system ClearWeatherEffects(); // Switches the time of day and checks climate logic to make sure that // weather and location are logical IsDayTime = !IsDayTime; Camera.main.backgroundColor = IsDayTime ? DayTime : NightTime; do { int v = UnityEngine.Random.Range(0, WeatherTypeCount); currentWeather = (Weather)v; if (currentWeather is Weather.Blizzard) { if (currentEncounterValue < 20) { int rollVal = UnityEngine.Random.Range(0, 5); if (rollVal > 0) continue; } } } while (ClimateLogicCheck() is false); // Gathers the weather effects needed from this component to instantiate GenerateWeatherEffects(); } /// <summary> /// Clears any lingering weather particle systems in the designated parent transform /// </summary> private void ClearWeatherEffects() { foreach (Transform child in effectObjectTransform) Destroy(child.gameObject); } /// <summary> /// Instantiates the particle systems for the current weather type /// </summary> private void GenerateWeatherEffects() { List<GameObject> effectList = new(); switch (currentWeather) { case Weather.Sunny: if (IsDayTime) effectList = sunnyEffects; else effectList = clearNightEffects; break; case Weather.Cloudy: effectList = cloudyEffects; break; case Weather.Rainy: effectList = rainyEffects; break; case Weather.Monsoon: effectList = monsoonEffects; break; case Weather.Snowy: effectList = snowyEffects; break; case Weather.Blizzard: effectList = blizzardEffects; break; case Weather.Foggy: effectList = foggyEffects; break; case Weather.Eclipsed: effectList = eclipseEffects; break; } foreach (GameObject effect in effectList) Instantiate(effect, effectObjectTransform); } /// <summary> /// Checks weather logic for better depth /// </summary> /// <param name="currentWeather">The current weather that is being checked for logic</param> /// <returns>False if the weather and time don't make sense, True otherwise</returns> private bool ClimateLogicCheck() { if (currentWeather is Weather.Eclipsed && !IsDayTime) return false; else if (IsDayTime && currentLocation is Locations.AbandonedManor) { Camera.main.backgroundColor = NightTime; return true; } else if (currentLocation is Locations.AbandonedManor && ( currentWeather is Weather.Sunny || currentWeather is Weather.Rainy || currentWeather is Weather.Monsoon || currentWeather is Weather.Snowy || currentWeather is Weather.Blizzard || currentWeather is Weather.Eclipsed )) { int v = UnityEngine.Random.Range(0, 100); currentWeather = v < 50 ? Weather.Cloudy : Weather.Foggy; return true; } // Further create logical climate phenomena return true; } /// <summary> /// Retrieves the current weather of the Encounter /// </summary> /// <returns>The weather of the Encounter</returns> public Weather GetWeather() => currentWeather; /// <summary> /// Sets the current location climate information of the current Encounter /// </summary> private void SetLocation(Locations locationInfo) { // Clear any lingering effects foreach (Transform child in spriteGridTransform) Destroy(child.gameObject); currentLocation = locationInfo; List<GameObject> spriteList = new(); // Gathers the sprites of the designated area and sets to instantiate switch (currentLocation) { case Locations.Swamplands: spriteList = swamplandSprites; break; case Locations.FrozenWasteland: spriteList = frozenWastelandSprites; break; case Locations.DarkVillage: spriteList = darkVillageSprites; break; case Locations.AbandonedManor: spriteList = abandonedManorSprites; break; case Locations.Village: spriteList = villageSprites; break; } Instantiate(spriteList[UnityEngine.Random.Range(0, spriteList.Count)], spriteGridTransform); SetWeather(); } /// <summary> /// Retrieves the current location of the Encounter /// </summary> /// <returns>The location of the Encounter</returns> public Locations GetLocation() => currentLocation; /// <summary> /// Deciphers the location of the encounter value to pull the necessary enemies out /// </summary> /// <param name="maxValue">Max Value reference that is -1 the encounter difficulty level to choose from the location selection</param> /// <returns>The string aspect to indicate which area the enemies should be loaded from</returns> /// <exception cref="InvalidDataException">If in some instance the location provides an invalid value an exception is thrown</exception> public string DecipherLocation(int encounterValue, object encounterType) { currentEncounterValue = encounterValue; int maxValue; if (encounterValue < 10) maxValue = 1; else if (encounterValue < 15) maxValue = 2; else if (encounterValue < 20) maxValue = 3; else maxValue = 4; if (encounterType is EnemyEncounter) { Locations location = (Locations)UnityEngine.Random.Range(0, maxValue); SetLocation(location); return location switch { Locations.Swamplands => "Swamplands", Locations.FrozenWasteland => "FrozenWasteland", Locations.DarkVillage => "DarkVillage", Locations.AbandonedManor => "AbandonedManor", _ => throw new InvalidDataException("The Location has provided an empty, invalid, or unavailable location."), }; } else { Locations location = Locations.Village; SetLocation(location); // Since only shops will indicate this type, it doesn't need a return value return string.Empty; } } /// <summary> /// Transforms the current weather in the Encounter to a new weather condition /// based on the parameter passed /// </summary> /// <param name="weatherToChangeTo">The new weather conditions</param> public void ManipulateWeather(Weather weatherToChangeTo) { // Clears any of the particle system effects for the current weather system ClearWeatherEffects(); // Sets and generates the new weather system effects currentWeather = weatherToChangeTo; GenerateWeatherEffects(); } public Locations GetRandomLocation() { if (currentEncounterValue < 10) return (Locations)UnityEngine.Random.Range(0, 1); else if (currentEncounterValue < 15) return (Locations)UnityEngine.Random.Range(0, 2); else if (currentEncounterValue < 20) return (Locations)UnityEngine.Random.Range(0, 3); else return (Locations)UnityEngine.Random.Range(0, 4); } }