/// <summary> /// Called by the OnEnemyTurnEnd event from EnemyMoveAttackAI after all enemies have moved. /// Starts Players Turn, Enables player to control characters /// </summary> private void StartPlayerTurn() { //Debug.Log("StartPlayerTurn"); _endTurnButt.interactable = true; _state = TurnState.PLAYERTURN; // We reset the turns of all characters // Allies foreach (Transform allyTrans in _allyParent) { MoveAttack allyMA = allyTrans.GetComponent <MoveAttack>(); if (allyMA != null) { allyMA.ResetMyTurn(); } else { Debug.LogError("There is no MoveAttack script attached to " + allyTrans.name); } } // Enemies foreach (Transform enemyTrans in _enemyParent) { MoveAttack enemyMA = enemyTrans.GetComponent <MoveAttack>(); if (enemyMA != null) { enemyMA.ResetMyTurn(); } else { Debug.LogError("There is no MoveAttack script attached to " + enemyTrans.name); } } // Call the event that the player's turn has begun if (OnBeginPlayerTurn != null) { //Debug.Log("OnBeginPlayerTurn"); OnBeginPlayerTurn(); } }
/// <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(); } } }
/// <summary> /// Finds and returns the tile this enemy should move to. /// Find the closest tile they can heal an enemy from /// </summary> /// <returns>Node that this enemy should move to</returns> override protected Node FindTileToMoveTo() { //Debug.Log("------------------------------------------"); //Debug.Log("Start Node " + StandingNode.Position); // 1) Get closest enemy node that can be healed Node closestEnemyNode = null; int closestEnemyF = int.MaxValue; Node closestHealNode = null; int closestHealF = int.MaxValue; // Iterate over each enemy to find the closest foreach (Transform charTrans in GetEnemyParent()) { // Only if the enemy is active and not this character if (charTrans.gameObject.activeInHierarchy && charTrans != this.transform) { // We only want to try moving there is the enemy is damaged Health charHealth = charTrans.GetComponent <Health>(); if (charHealth.CurHP < charHealth.MaxHP) { Node charNode = MAContRef.GetNodeByWorldPosition(charTrans.position); // Path to that enemy MAContRef.Pathing(StandingNode, charNode, CharacterType.Enemy, false); // FOR TESTING //Vector2Int printPos = new Vector2Int(int.MaxValue, int.MaxValue); //if (closestAllyNode != null) // printPos = closestAllyNode.Position; //Debug.Log(charNode.Position + " with " + charNode.F + " is being compared with " + printPos + " with " + closestAllyF); // If it is closer than the currently closest enemy if (closestEnemyF > charNode.F) { int charFVal = charNode.F; //Debug.Log("It was closer in distance"); // 2) Get the closest node this enemy could heal that enemy from // We know that is enemy is closer in walking distance, but we don't know if they have any openings to heal // So we test to see if we can find any openings to heal // Get the potential nodes to heal from List <Node> potHealNodes = MAContRef.GetNodesDistFromNode(charNode, MARef.AttackRange); // Figure out which is closest to the standing positions //Debug.Log("The attack nodes are at "); foreach (Node curAdjNode in potHealNodes) { //Debug.Log(curAdjNode.Position); // If the node is not occupied by someone other than this enemy // since if this enemy is standing next to an ally, obvious that ally is the closest MoveAttack curAdjEnemyMARef = MAContRef.GetCharacterMAByNode(curAdjNode); if (curAdjNode.Occupying == CharacterType.None || curAdjEnemyMARef == MARef) { // Path there, if succesful, then see if it is closer than the current attackfrom node // We say we don't care if we can get there (shouldCare=false) because we have already // checked if someone was there and if there is someone there, it would be this enemy if (MAContRef.Pathing(StandingNode, curAdjNode, CharacterType.Enemy, false)) { // If it is closer than the closest attack from node if (closestHealF > curAdjNode.F) { //Debug.Log("It was closer and could be attacked"); // It is the new closest enemy node closestEnemyNode = charNode; closestEnemyF = charFVal; // It is the new closest heal node closestHealNode = curAdjNode; closestHealF = curAdjNode.F; } } } } } } } } // If there is no closest heal from node, make the enemy run away if (closestHealNode == null) { // Get the allies nodes before (we only want the allies who are close enough // that they could attack us on their next turn) List <Node> allyNodes = new List <Node>(); foreach (Transform allyTrans in GetAllyParent()) { Node curAllyNode = MAContRef.GetNodeByWorldPosition(allyTrans.position); // Calculate the distance between the ally's node and this enemy's node Vector2Int distVect = curAllyNode.Position - StandingNode.Position; int dist = Mathf.Abs(distVect.x + distVect.y); // Only add the ally if the enemy is within their attack range MoveAttack curAllyMA = MAContRef.GetCharacterMAByNode(curAllyNode); curAllyMA.ResetMyTurn(); //Debug.Log("Dist from " + curAllyMA.name + ": " + dist + ". " + curAllyNode.Position + "->" + StandingNode.Position); if (dist <= curAllyMA.AttackRange + curAllyMA.MoveRange) { //Debug.Log(curAllyMA.name + " is close enough to " + this.name); allyNodes.Add(curAllyNode); } } // Set a reference to the node that is the farthest from all allies Node furthestNode = StandingNode; int furthestF = 0; // Get the move tiles of this enemy plus the node they are standing on List <Node> testNodes = new List <Node>(MARef.MoveTiles); testNodes.Add(StandingNode); // Iterate over this enemy's move tiles foreach (Node moveTile in testNodes) { int curAddedF = 0; // Path from each ally to the current tile foreach (Node curAllyNode in allyNodes) { MAContRef.Pathing(curAllyNode, moveTile, CharacterType.Enemy, false); curAddedF += moveTile.F; } // If the distance from each ally is greater than the last distance, it is the new furthest if (curAddedF > furthestF) { furthestNode = moveTile; furthestF = curAddedF; } } // Return the furthest node return(furthestNode); } //Debug.Log("The closest ally is at " + closestAllyNode.Position); // Short cut. If the closest attack node is one of the moveTiles, just return it // Iterate over the possible tiles to move to if (MARef.MoveTiles != null) { foreach (Node moveTile in MARef.MoveTiles) { // If its a part of the movetiles if (moveTile == closestHealNode) { return(closestHealNode); } } } else { Debug.LogError("MoveTiles is null"); } // If the shortcut didn't work do it the long way Node closestNode = StandingNode; int closestF = int.MaxValue; if (MARef.MoveTiles != null) { // Iterate over the possible tiles to move to foreach (Node moveTile in MARef.MoveTiles) { // Path from that move tile to the closest attack node // If successful, check if its closer than the closestNode if (MAContRef.Pathing(moveTile, closestHealNode, CharacterType.Enemy)) { // It its closer, its the new closestNode if (closestF > closestHealNode.F) { closestNode = moveTile; closestF = closestHealNode.F; } } } } else { Debug.LogError("MoveTiles is null"); } // Its the endtile return(closestNode); }