Encounter / Assets / Scripts / BattleLogic / PositionHandler.cs
PositionHandler.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;

public class PositionHandler : MonoBehaviour
{
    public static PositionHandler Instance { get; private set; }

    [Header("Positions")]
    [SerializeField] private List<Transform> player_Loc;        // Reference to the transforms that the players can be located at
    [SerializeField] private List<Transform> enemy_Locs;        // Reference to the transforms that the enemies can be located at
    [SerializeField] private List<Transform> member_Locs;       // Reference to the transforms that the members can be located at 
    [SerializeField] private Transform leftAllLocation;
    [SerializeField] private Transform rightAllLocation;
    [SerializeField] private Transform topOfScreenPosition;
    [SerializeField] private Transform bottomOfScreenPosition;
    [SerializeField] private Transform centerOfScreenPosition;

    [Header("Spawning Materials")]
    [SerializeField] private Material bossSpawnMaterial;
    [SerializeField] private AudioClip bossSpawnSFX;

    private void Awake()
    {
        Instance = this;
    }
    /// <summary>
    /// Spawns the player game object within the player position from the handler
    /// </summary>
    /// <param name="player">Player game object</param>
    /// <returns>The spawned game object reference</returns>
    public GameObject PositionPlayer(GameObject player)
    {
        GameObject playerInstance = Instantiate(player, player_Loc.First(), false);
        playerInstance.GetComponent<Player>().DeactivateVisually();
        return playerInstance;
    }
    public GameObject[] PositionAlly(GameObject[] allies)
    {
        if (allies is null)
            return null;

        int counter = 0;
        foreach (GameObject ally in allies)
        {
            if (ally == null)
                continue;
            else
                ++counter;
        }

        GameObject[] spawnedAllies = new GameObject[counter];

        for (int i = 0; i < counter; i++)
        {
            spawnedAllies[i] = Instantiate(allies[i], member_Locs[i], false);
            spawnedAllies[i].GetComponentInChildren<SpriteRenderer>().sortingOrder = i + 1;
            spawnedAllies[i].GetComponent<Ally>().DeactivateVisually();
        }

        List<GameObject> allyGUIs = GeneralUI.Instance.GetAllyIconGUIs();
        for (int i = 0; i < allyGUIs.Count; i++)
        {
            string allyGuiName = allyGUIs[i].GetComponent<PartyMemberGUI>().GetAllyInfo().GetName();
            foreach (GameObject spawnedAlly in spawnedAllies)
            {
                if (allyGuiName.Equals(spawnedAlly.GetComponent<Ally>().GetName()))
                {
                    spawnedAlly.GetComponent<Ally>().InjectGUI(allyGUIs[i].GetComponent<PartyMemberGUI>());
                    break;
                }
            }
        }

        return spawnedAllies;
    }
    public void ShowAndRaisePlayerObject(GameObject playerObject)
    {
        if (playerObject.transform.parent != player_Loc[0])
        {
            playerObject.transform.SetParent(player_Loc[0]);
            playerObject.transform.localPosition = Vector3.zero;
        }

        // Re-enable sprite functionality
        playerObject.GetComponent<Player>().ReactivateVisually();

        // Raise to 1 and drop
        playerObject.transform.position = new Vector3(playerObject.transform.position.x, playerObject.transform.position.y + 1f, playerObject.transform.position.z);
        playerObject.GetComponent<Target>().ReactivateDrop();
    }
    public void ShowAndRaiseAllyObjects(GameObject[] allyObjects)
    {
        int posCounter = 0;
        foreach (GameObject allyObject in allyObjects)
        {
            if (allyObject.transform.parent != member_Locs[posCounter])
            {
                allyObject.transform.SetParent(member_Locs[posCounter]);
                allyObject.transform.localPosition = Vector3.zero;
            }

            // Re-enable sprite functionality
            allyObject.GetComponent<Ally>().ReactivateVisually();

            // Raise to 1 and drop
            allyObject.transform.position = new Vector3(allyObject.transform.position.x, allyObject.transform.position.y + 1f, allyObject.transform.position.z);
            allyObject.GetComponent<Target>().ReactivateDrop();

            posCounter++;
        }
    }
    /// <summary>
    /// Positions the enemy sprites into the locations set within the field
    /// </summary>
    /// <param name="enemies">The enemy game objects to set within the field</param>
    /// <returns>The enemy components from the game objects</returns>
    public (GameObject[], Enemy[]) PositionEnemies(GameObject[] enemies, BattleHandler bh, bool isBoss)
    {
        GameObject[] enemyObjects = new GameObject[enemies.Length];

        int positionCounter = 0;
        for (int i = 0; i < enemies.Length; i++)
        {
            if (isBoss)
            {
                enemyObjects[0] = SpawnBoss(enemies[0]).GetAwaiter().GetResult();
                break;
            }

            // Put space between legendary enemies if available
            if (enemies[i].GetComponent<Enemy>().GetEnemyDifficulty() is Enemy.DifficultyRating.Legendary && positionCounter < 4)
            {
                positionCounter++;
                enemyObjects[i] = Instantiate(enemies[i], enemy_Locs[positionCounter++], false);
            }
            else
                enemyObjects[i] = Instantiate(enemies[i], enemy_Locs[positionCounter++], false);
        }

        Enemy[] compColl = new Enemy[enemyObjects.Length];
        for (int i = 0; i < compColl.Length; i++)
        {
            compColl[i] = enemyObjects[i].GetComponent<Enemy>();
            compColl[i].InjectHandler(bh);
        }

        return (enemyObjects, compColl);
    }
    public async Task<GameObject> SpawnBoss(GameObject boss)
    {
        GameObject bossObject = Instantiate(boss, enemy_Locs[1], false);
        bossObject.GetComponentInChildren<SpriteRenderer>().material = bossSpawnMaterial;

        Color bossColor = bossObject.GetComponentInChildren<SpriteRenderer>().color;

        // Spawn higher with 4 extra units up in the Y
        Vector3 bossPosition = bossObject.transform.position;
        bossObject.transform.position = new Vector3(bossPosition.x, bossPosition.y + 4f, bossPosition.z);

        // Transparent color and a material that shows energy forming around the entity
        StartCoroutine(WhitenBoss(bossColor));
        bossObject.transform.GetChild(bossObject.transform.childCount - 1).GetChild(0).gameObject.SetActive(true);
        Transform subParticleObject = bossObject.transform.GetChild(bossObject.transform.childCount - 1).GetChild(0);

        // Wait for the energy to coalesce around the boss before triggering a large shockwave and coloring the boss
        await Task.Delay(3000);
        subParticleObject.GetComponent<ParticleSystem>().TriggerSubEmitter(0);
        SoundManager.Instance.PlaySoundFX(bossSpawnSFX);

        bossObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
        await bossObject.GetComponent<Boss>().PlayEncounterEffect();

        return bossObject;
    }
    private IEnumerator WhitenBoss(Color bossColor)
    {
        while (bossColor.a < 1f)
        {
            bossColor = new Color(bossColor.r, bossColor.g, bossColor.b, bossColor.a + (.1f * Time.deltaTime));

            yield return null;
        }

        yield return null;
    }
    /// <summary>
    /// Creates a temporary minion for either the left or right side
    /// </summary>
    /// <param name="minion">The object to instantiate</param>
    /// <param name="isLeft">If true then it will be added to allies, otherwise add to enemies</param>
    public GameObject InjectMinion(GameObject minion, bool isLeft)
    {
        GameObject createdMinion = null;
        if (isLeft)
        {
            for (int i = 0; i < member_Locs.Count; i++)
            {
                if (member_Locs[i].childCount is 0)
                {
                    createdMinion = Instantiate(minion, member_Locs[i]);
                    break;
                }
            }
        }
        else
        {
            for (int i = 0; i < enemy_Locs.Count; i++)
            {
                if (enemy_Locs[i].childCount is 0)
                {
                    createdMinion = Instantiate(minion, enemy_Locs[i]);

                    break;
                }
                else if (!enemy_Locs[i].GetChild(0).TryGetComponent(out Enemy _))
                {
                    // If false, means an effect object is present so just put the enemy here
                    createdMinion = Instantiate(minion, enemy_Locs[i]);

                    break;
                }
            }
        }

        return createdMinion;
    }
    public int GatherLocationCount(int transformCountIndicator, bool wasEnemyCast)
    {
        return transformCountIndicator switch
        {
            5 => wasEnemyCast ? GatherLocationCount(6, wasEnemyCast) : GatherLocationCount(8, wasEnemyCast),
            6 => enemy_Locs.Where(enemy => enemy.childCount is not 0 && enemy.GetComponent<Enemy>().HasDied is false).Count(),
            8 => (player_Loc[0].childCount is not 0 && player_Loc[0].GetComponent<Player>().HasDied is false ? 1 : 0) +
                 member_Locs.Where(companion => companion.childCount is not 0 && companion.GetComponent<Ally>().HasDied is false).Count(),

            _ => 1,
        };
    }
    public Transform[] GatherLocation(SpellVisualEffects.EffectLocation effectLocation, int castingLocation, int targetLocation, bool wasEnemyCast, bool isTargettingSameSide)
    {
        switch (effectLocation)
        {
            case SpellVisualEffects.EffectLocation.SelfLocation:
                Transform[] selfLocation = new Transform[1];
                selfLocation[0] = wasEnemyCast ? enemy_Locs[castingLocation] : (castingLocation is 0 ? player_Loc[castingLocation] : member_Locs[castingLocation - 1]);
                return selfLocation;
            case SpellVisualEffects.EffectLocation.TargettedLocation:
                Transform[] targettedLocation = new Transform[1];
                if (!isTargettingSameSide)
                    targettedLocation[0] = wasEnemyCast ? (targetLocation is 0 ? player_Loc[targetLocation] : member_Locs[targetLocation - 1]) : enemy_Locs[targetLocation];
                else
                    targettedLocation[0] = wasEnemyCast ? enemy_Locs[targetLocation] : (targetLocation is 0 ? player_Loc[targetLocation] : member_Locs[targetLocation - 1]);

                return targettedLocation;
            case SpellVisualEffects.EffectLocation.TravelSelfToTarget:
                Transform[] selfToTarget = new Transform[1];
                selfToTarget[0] = wasEnemyCast ? enemy_Locs[castingLocation] : (castingLocation is 0 ? player_Loc[castingLocation] : member_Locs[castingLocation - 1]);
                return selfToTarget;
            case SpellVisualEffects.EffectLocation.TravelTargetToSelf:
                Transform[] targetToSelf = new Transform[1];
                targetToSelf[0] = wasEnemyCast ? (targetLocation is 0 ? player_Loc[targetLocation] : member_Locs[targetLocation - 1]) : enemy_Locs[targetLocation];
                return targetToSelf;
            case SpellVisualEffects.EffectLocation.AllSide:
                Transform[] allSideTransform = new Transform[1];
                allSideTransform[0] = wasEnemyCast ? leftAllLocation : rightAllLocation;
                return allSideTransform;
            case SpellVisualEffects.EffectLocation.AllSideEachLocation:
                if (wasEnemyCast)
                    return GatherLocation(SpellVisualEffects.EffectLocation.AllLeftLocations, castingLocation, targetLocation, wasEnemyCast, isTargettingSameSide);
                else
                    return GatherLocation(SpellVisualEffects.EffectLocation.AllRightLocations, castingLocation, targetLocation, wasEnemyCast, isTargettingSameSide);

            case SpellVisualEffects.EffectLocation.AllRightLocations:
                return enemy_Locs.Where(enemyPos => enemyPos.childCount is not 0 && enemyPos.GetComponent<Enemy>().HasDied is false).ToArray();
            case SpellVisualEffects.EffectLocation.AllRightCenter:
                Transform[] allRightCenter = new Transform[1];
                allRightCenter[0] = rightAllLocation;
                return allRightCenter;
            case SpellVisualEffects.EffectLocation.AllLeftLocations:
                return member_Locs.Where(memberPos => memberPos.childCount is not 0 && memberPos.GetComponent<Ally>().HasDied is false)
                        .Concat(player_Loc.Where(playerPos => playerPos.childCount is not 0 && playerPos.GetComponent<Player>().HasDied is false)).ToArray();
            case SpellVisualEffects.EffectLocation.AllLeftCenter:
                Transform[] allLeftCenter = new Transform[1];
                allLeftCenter[0] = leftAllLocation;
                return allLeftCenter;
            case SpellVisualEffects.EffectLocation.TopOfScreen:
                Transform[] topScreen = new Transform[1];
                topScreen[0] = topOfScreenPosition;
                return topScreen;
            case SpellVisualEffects.EffectLocation.CenterOfScreen:
                Transform[] centerScreen = new Transform[1];
                centerScreen[0] = centerOfScreenPosition;
                return centerScreen;
            case SpellVisualEffects.EffectLocation.BottomOfScreen:
                Transform[] bottomScreen = new Transform[1];
                bottomScreen[0] = bottomOfScreenPosition;
                return bottomScreen;
            default:
                throw new InvalidEnumArgumentException();
        }
    }
    public int GetEntityPositionIndex(Entity entity)
    {
        if (entity is Player)
            return 0;
        else if (entity is Ally)
        {
            int index = 1;
            foreach (Transform memberLocation in member_Locs)
            {
                if (memberLocation.childCount > 0)
                {
                    if (memberLocation.GetChild(0).GetComponent<Ally>().GetUniqueID() == entity.GetUniqueID())
                            return index;
                    else
                        index++;
                }
            }
        }
        else
        {
            int index = 0;
            foreach (Transform enemyLocation in enemy_Locs)
            {
                if (enemyLocation.childCount > 0)
                {
                    if (enemyLocation.GetChild(0).GetComponent<Enemy>().GetUniqueID() == entity.GetUniqueID())
                        return index;
                }
                else
                    index++;
            }
        }

        return -1;
    }
    public int GetEmptyPosition(Entity spellUser)
    {
        if (spellUser is Ally || spellUser is Player)
        {
            if (member_Locs[0].childCount is 0)
                return 1;
            else if (member_Locs[1].childCount is 0)
                return 2;
            else if (member_Locs[2].childCount is 0)
                return 3;
        }
        else
        {
            if (enemy_Locs[0].childCount is 0)
                return 0;
            else if (enemy_Locs[1].childCount is 0)
                return 1;
            else if (enemy_Locs[2].childCount is 0)
                return 2;
            else if (enemy_Locs[3].childCount is 0)
                return 3;
        }

        return -1;
    }
}