Encounter / Assets / Scripts / ClimateManager.cs
ClimateManager.cs
Raw
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);
    }
}