Exemple #1
0
    /// <summary>
    /// Tries to start moving the selected character to the node that was just selected
    /// or tries to go to hit the enemy at the selected node
    /// </summary>
    /// <param name="selNode">The node that was just selected</param>
    /// <returns>Returns true if the character will do an action, false if they just got deselected</returns>
    private bool AttemptMoveOrAttackOrInteract(Node selNode)
    {
        MoveAttack charAtNode = _mAContRef.GetCharacterMAByNode(selNode);

        // If the current character can move there
        if (_charSelected.MoveTiles.Contains(selNode) && selNode.Occupying == CharacterType.None)
        {
            // We want the user to be able to select after moving, so
            // when the ally finishes moving, return control
            MoveAttack.OnCharacterFinishedMoving += ReturnControlAfterMove;

            // Start moving the ally
            Node startNode = _mAContRef.GetNodeByWorldPosition(_charSelected.transform.position);
            DoMove(startNode, selNode);

            return(true);
        }
        // If the current character can attack there (and wants to attack), and there is an (active) enemy there.
        // Then we want the current character to walk to the closest node to there and attack
        else if (_charSelected.AttackTiles.Contains(selNode) && !_charSelected.TargetFriendly && charAtNode != null &&
                 charAtNode.WhatAmI == CharacterType.Enemy && charAtNode.gameObject.activeInHierarchy)
        {
            AttemptMoveAndAttack(selNode);
            return(true);
        }
        // If the current character can heal/buff there (and wants to), and there is an ally there.
        // Then we want the current character to walk to the closest node to there and heal/buff
        else if (_charSelected.AttackTiles.Contains(selNode) && _charSelected.TargetFriendly && charAtNode != null &&
                 charAtNode.WhatAmI == CharacterType.Ally && charAtNode != _charSelected)
        {
            AttemptMoveAndAttack(selNode);
            return(true);
        }
        // If the current character can interact there, and there is an interactable thing there
        else if (_charSelected.InteractTiles.Contains(selNode) && selNode.Occupying == CharacterType.Interactable)
        {
            AttemptMoveAndInteract(selNode);
            return(true);
        }
        // If none of the above, just deselect them
        else
        {
            Deselect();
            return(false);
        }
    }
    /// <summary>
    /// Has the current enemy move and then increments it so that the next time this is called, the next enemy will move
    /// </summary>
    private IEnumerator NextEnemy()
    {
        // So that the this enemy can't start until the previous one is done
        while (_duringEnemyTurn)
        {
            yield return(null);
        }
        _duringEnemyTurn = true;

        if (_enemyIndex < _enemiesMA.Count)
        {
            // Try to get the current enemy we should move
            _currentEnemy = _enemiesMA[_enemyIndex];
            // If the enemy does not exist, do not try to move it
            if (_currentEnemy != null)
            {
                // Call the begin single enemy event
                if (OnBeginSingleEnemy != null)
                {
                    OnBeginSingleEnemy(_currentEnemy);
                }


                //Debug.Log("Begin " + _currentEnemy.name + "'s turn");
                // See if the current enemy will be active
                Node enemyNode = _mAContRef.GetNodeByWorldPosition(_currentEnemy.transform.position);
                for (int i = 0; i < _alliesMA.Count; ++i)
                {
                    MoveAttack ally = _alliesMA[i];
                    // Make sure the enemy exists
                    if (ally == null)
                    {
                        _alliesMA.RemoveAt(i);
                        --i;
                        continue;
                    }

                    Node allyNode = _mAContRef.GetNodeByWorldPosition(ally.transform.position);
                    if (Mathf.Abs(enemyNode.Position.x - allyNode.Position.x) + Mathf.Abs(enemyNode.Position.y - allyNode.Position.y) <= _aggroRange)
                    {
                        break;
                    }
                }
            }
            // Have the current enemy take their turn
            // Now called from the CamFollow OnFinishEnemyPan event
            //TakeSingleTurn();
        }
        else
        {
            //Debug.Log("All enemies done");
            if (OnEnemyTurnEnd != null)
            {
                OnEnemyTurnEnd();
            }
        }

        _duringEnemyTurn = false;
        yield return(null);
    }
Exemple #3
0
    /// <summary>
    /// Takes the turn of the enemy
    /// </summary>
    public void TakeTurn()
    {
        // Reset my turn
        _mARef.ResetMyTurn();

        // Get the node this enemy is standing on
        _standingNode = _mAContRef.GetNodeByWorldPosition(this.transform.position);
        // We are going to use the enemy's move tiles, so we need to recalculate those,
        // since other characters have probably moved on their turn
        _mARef.CalculateAllTiles();
        // Find the tile the enemy should move to
        Node nodeToMoveTo = FindTileToMoveTo();

        // Make sure we have a place to move
        if (nodeToMoveTo != null)
        {
            // After the enemy finishes moving, it will call the CharacterFinishedMovingEvent.
            // So we add the BeginAttemptAction function to be called when that event is called.
            // It will remove itself from the event once it is called.
            // The idea is that only one function will be attached to that event at a time (will belong to current character)
            MoveAttack.OnCharacterFinishedMoving += BeginAttemptAction;
            // Start moving the enemy
            MoveToTile(nodeToMoveTo);

            /// We want the enemy's turn to look like Move, Action, End.
            /// But we only call MoveToTile above.
            /// This is because we need the enemy to finish moving before it does its action.
            /// Action is called when the character finishes moving.
            /// Similarly, End is called when the character finishes its action.
        }
        // If we have no where to move, just finish this enemy's turn
        else
        {
            // Call the finish enemy turn event
            if (OnSingleEnemyFinish != null)
            {
                OnSingleEnemyFinish();
            }
        }
    }
Exemple #4
0
    /// <summary>
    /// Actually destroys the object. Should only be called by an animation event
    /// </summary>
    protected virtual void Ascend()
    {
        // Since this is done, we need to let other character move to where this just was
        Node myNode = _mAContRef.GetNodeByWorldPosition(this.transform.position);

        myNode.Occupying = CharacterType.None;
        // We need to move this character out from the character's parent before we recalculate the visuals, or this will be included in those calculaiton
        GameObject graveyard = new GameObject("Graveyard");

        this.transform.parent = graveyard.transform;
        // We then need to recreate all the visuals, so that the user can see they can move over the dead body
        //NEEDTOFIXmAContRef.CreateAllVisualTiles();

        // Call the OnCharacterDeath event
        OnCharacterDeath?.Invoke();

        // Remove the ongoing action to signal we are done
        MoveAttack.RemoveOngoingAction();

        //Debug.Log(this.gameObject.name + " has died");
        Destroy(graveyard);
        Destroy(this.gameObject);
    }
    /// <summary>
    /// Finds and saves the nodes that can be moved to, attacked, and interacted with in the
    /// appropriate lists.
    /// Called from MoveAttackGUIController when this character is selected
    /// </summary>
    public void CalculateAllTiles()
    {
        // Initialize the three lists
        _moveTiles     = new List <Node>();
        _attackTiles   = new List <Node>();
        _interactTiles = new List <Node>();

        // Get the node this character is currently standing at
        Node startNode = _mAContRef.GetNodeByWorldPosition(this.transform.position);

        // This list is what has already been tested
        List <Node> testedNodes = new List <Node>();

        // This list holds the nodes that have yet to be tested for validity
        List <Node> currentNodes = new List <Node>();

        currentNodes.Add(startNode);

        // This list holds the move nodes that are "edge" tiles and have something we can interact/attack/buff near them
        List <Node> edgeMoveNodes = new List <Node>();

        edgeMoveNodes.Add(startNode);

        // This is how many iterations of checks we have gone over. Aka, how many tiles have been traversed in one path
        int depth = 0;

        // 1. First iterate only over the range of tiles we can move
        while (depth < _moveRange)
        {
            int amountNodes = currentNodes.Count;
            for (int i = 0; i < amountNodes; ++i)
            {
                // If the current node is null, end this iteration and start the next one
                if (currentNodes[i] != null)
                {
                    Vector2Int curNodePos = currentNodes[i].Position;
                    // Check above node
                    Vector2Int testPos      = curNodePos + Vector2Int.up;
                    bool       isAboveValid = MoveTestNode(testPos, testedNodes, currentNodes);

                    // Check left node
                    testPos = curNodePos + Vector2Int.left;
                    bool isLeftValid = MoveTestNode(testPos, testedNodes, currentNodes);

                    // Check right node
                    testPos = curNodePos + Vector2Int.right;
                    bool isRightValid = MoveTestNode(testPos, testedNodes, currentNodes);

                    // Check down node
                    testPos = curNodePos + Vector2Int.down;
                    bool isDownValid = MoveTestNode(testPos, testedNodes, currentNodes);


                    // If they were not all valid, then there is something adjacent to the cur tile where
                    // we should put an attack/interactable tile. So add it to edge tiles
                    if (!(isAboveValid && isLeftValid && isRightValid && isDownValid) &&
                        currentNodes[i].Occupying == CharacterType.None)
                    {
                        edgeMoveNodes.Add(currentNodes[i]);
                    }
                }
            }
            // Removes the nodes that have already been iterated over
            for (int i = 0; i < amountNodes; ++i)
            {
                currentNodes.RemoveAt(0);
            }
            ++depth;
        }
        // All the remaining currentNodes are edge tiles (as long as no one is there)
        foreach (Node n in currentNodes)
        {
            if (n.Occupying == CharacterType.None)
            {
                edgeMoveNodes.Add(n);
            }
        }

        // Reset the tested nodes, since we do not care if the tiles were already tested for movement, since they could have failed
        // those tested due to them being an interactable/attack tile
        testedNodes = new List <Node>();
        // 2. Now iterate 4-way over the edge tiles to check for interactables (There is no need for a while statement,
        // since we are only iterating one more tile, but it keeps it looking similar)
        while (depth < _moveRange + 1)
        {
            int amountNodes = edgeMoveNodes.Count;
            for (int i = 0; i < amountNodes; ++i)
            {
                // If the current node is null, end this iteration and start the next one
                if (edgeMoveNodes[i] != null)
                {
                    Vector2Int curNodePos = edgeMoveNodes[i].Position;
                    // Check above node
                    Vector2Int testPos = curNodePos + Vector2Int.up;
                    InteractTestNode(testPos, testedNodes, edgeMoveNodes);

                    // Check left node
                    testPos = curNodePos + Vector2Int.left;
                    InteractTestNode(testPos, testedNodes, edgeMoveNodes);

                    // Check right node
                    testPos = curNodePos + Vector2Int.right;
                    InteractTestNode(testPos, testedNodes, edgeMoveNodes);

                    // Check down node
                    testPos = curNodePos + Vector2Int.down;
                    InteractTestNode(testPos, testedNodes, edgeMoveNodes);
                }
            }
            // Removes the nodes that have already been iterated over
            for (int i = 0; i < amountNodes; ++i)
            {
                edgeMoveNodes.RemoveAt(0);
            }
            ++depth;
        }
        // 3. Finally, iterate over the remaining depth to check for attacking
        while (depth < _moveRange + _attackRange)
        {
            int amountNodes = edgeMoveNodes.Count;
            for (int i = 0; i < amountNodes; ++i)
            {
                // If the current node is null, end this iteration and start the next one
                if (edgeMoveNodes[i] != null)
                {
                    Vector2Int curNodePos = edgeMoveNodes[i].Position;
                    // Check above node
                    Vector2Int testPos = curNodePos + Vector2Int.up;
                    AttackTestNode(testPos, testedNodes, edgeMoveNodes);

                    // Check left node
                    testPos = curNodePos + Vector2Int.left;
                    AttackTestNode(testPos, testedNodes, edgeMoveNodes);

                    // Check right node
                    testPos = curNodePos + Vector2Int.right;
                    AttackTestNode(testPos, testedNodes, edgeMoveNodes);

                    // Check down node
                    testPos = curNodePos + Vector2Int.down;
                    AttackTestNode(testPos, testedNodes, edgeMoveNodes);
                }
            }
            // Removes the nodes that have already been iterated over
            for (int i = 0; i < amountNodes; ++i)
            {
                edgeMoveNodes.RemoveAt(0);
            }
            ++depth;
        }
    }