/// <summary> /// Attempts to do whatever action this enemy does. /// Called after the character finishes moving. /// If the enemy is within range of an ally, it will push them. /// </summary> protected override void AttemptAction() { Node currentNode = MAContRef.GetNodeByWorldPosition(this.transform.position); // Get the nodes it can push List <Node> adjNodes = MAContRef.GetNodesDistFromNode(currentNode, 1); // Try to find an ally to push at any of these nodes Node nodeToAttack = null; foreach (Node curNode in adjNodes) { // If we found a node containing an ally if (curNode.Occupying == CharacterType.Ally) { nodeToAttack = curNode; break; } } // If we found an ally to push, push it if (nodeToAttack != null) { MARef.StartAttack(nodeToAttack.Position); } // Otherwise, just end the attack else { MARef.EndAttack(); } }
/// <summary> /// Attempts to do whatever action this enemy does. /// Called after the character finishes moving. /// Uses the character's skill on an enemy in range. /// </summary> override protected void AttemptAction() { // Recalculate the enemy's move and attack tiles. // We really only want their attack tiles, but those are based on the move tiles // Which are currently out of place since they are what the MARef.CalculateAllTiles(); Vector2Int nodeToAttack = new Vector2Int(int.MaxValue, int.MaxValue); // Try to find an ally in range //Debug.Log("These are " + this.name + " at " + this.transform.position + " potential attack tiles: "); foreach (Node atkNode in MARef.AttackTiles) { //Debug.Log(atkNode.Position); MoveAttack potAlly = MAContRef.GetCharacterMAByNode(atkNode); // If we found an ally at that tile if (potAlly != null && potAlly.WhatAmI == CharacterType.Ally) { //Debug.Log("Attacking ^ That tile"); nodeToAttack = atkNode.Position; break; } } // If there is no node to attack, just end the attack if (nodeToAttack.x == int.MaxValue && nodeToAttack.y == int.MaxValue) { MARef.EndAttack(); } // If there is a node being attacked, start the attack else { MARef.StartAttack(nodeToAttack); } }
/// <summary> /// Finds and returns the tile this enemy should move to. /// Specified in the overrides. /// </summary> /// <returns>Node that this enemy should move to</returns> protected override Node FindTileToMoveTo() { // 1) Find the closest ally Node closestAllyNode = null; int closestAllyF = int.MaxValue; // Iterate over each ally to find the closest foreach (Transform charTrans in GetAllyParent()) { // Get the node that character is on Node charNode = MAContRef.GetNodeByWorldPosition(charTrans.position); // Path to that ally MAContRef.Pathing(StandingNode, charNode, CharacterType.Enemy, false); // If it is closer than the currently closest ally if (closestAllyF > charNode.F) { closestAllyNode = charNode; closestAllyF = charNode.F; } } // If there is no closest ally node, we return the node the enemy is currently on if (closestAllyNode == null) { //Debug.Log("There was no closest Ally"); return(StandingNode); } // 2) Find the path from that ally to the exit // Find the exit GameObject stairsObj = GameObject.Find(ProceduralGenerationController.STAIRS_NAME); Node stairsNode = MAContRef.GetNodeByWorldPosition(stairsObj.transform.position); // Initialize the list of nodes in the ally's path // This path is the one the ally would take if they did not care about enemies in their path List <Node> allyStraightPathToExit = new List <Node>(); // Path from that ally to the exit // We say we don't care in the case that there is an enemy covering the exit if (MAContRef.Pathing(closestAllyNode, stairsNode, CharacterType.Enemy, false)) { // Store this path Node curNode = closestAllyNode; while (curNode.WhereToGo != curNode) { curNode = curNode.WhereToGo; allyStraightPathToExit.Add(curNode); } } // Iterate over this straight path to get the actual path the ally would have to take List <Node> allyActualPathToExit = new List <Node>(); for (int i = 0; i < allyStraightPathToExit.Count; ++i) { Node curNode = allyStraightPathToExit[i]; // If the ally could actually go here, add the node to the allyActualPath if (curNode.Occupying == CharacterType.None || curNode.Occupying == CharacterType.Ally) { allyActualPathToExit.Add(curNode); } // If the ally could not actually go here, find the next unoccupied node and // try to path from the previous node to the next unoccupied ndoe else { // Get the previous node Node prevNode = null; if (allyActualPathToExit.Count > 0) { prevNode = allyActualPathToExit[allyActualPathToExit.Count - 1]; } else { prevNode = closestAllyNode; } // Find next unoccupied node // If there are no more unoccupied nodes, then we just have the unoccupied node be the last node Node unoccNode = allyStraightPathToExit[allyStraightPathToExit.Count - 1]; for (int k = i + 1; k < allyStraightPathToExit.Count; ++k) { Node curTestNode = allyStraightPathToExit[k]; // If we found the unoccupied node if (curTestNode.Occupying == CharacterType.None || curTestNode.Occupying == CharacterType.Ally) { unoccNode = curTestNode; break; } } // Path from the previous node to the unoccupied node (we don't care if we can // actually make it there in case there was no unoccupied node) if (MAContRef.Pathing(prevNode, unoccNode, CharacterType.Ally, false)) { // Add this path to the actual path (we don't add the first or last node) Node subPathNode = prevNode.WhereToGo; while (subPathNode.WhereToGo != subPathNode) { allyActualPathToExit.Add(subPathNode); subPathNode = subPathNode.WhereToGo; } } // If the pathing fails, we have made the full path the enemy can take right now else { break; } } } // 3) Find the closest node in this path to the enemy // We start by pathing to the first one and iterating. If the distance to a node // ever increases, that node is farther away, and the rest will be too, so we stop there Node targetNode = null; // The settle node is the node we will get close to if we can't reach any of the nodes in the path Node settleNode = StandingNode; int settleF = int.MaxValue; foreach (Node curNode in allyActualPathToExit) { // If we are already there or could actually move to there right now, we found our node if (curNode == StandingNode || MARef.MoveTiles.Contains(curNode)) { targetNode = curNode; break; } // If we cannot instantly reach this tile, see how far it is away from this enemy // If we succesfully pathed there, compare the distance if (MAContRef.Pathing(StandingNode, curNode, CharacterType.Enemy)) { // If the current node's F is smaller than the settleF, this node is closer if (settleF > curNode.F) { settleNode = curNode; settleF = curNode.F; } // If it is farther away, all other ones will be farther away too, so dont keep testing else { break; } } } // If we found a target node we can move to immediately, return it if (targetNode != null) { return(targetNode); } // If we did not find a target node, find node closest to the settle node that we can reach else { Node closestNode = StandingNode; int closestF = int.MaxValue; // Iterate over the possible tiles to move to foreach (Node moveTile in MARef.MoveTiles) { // Path from that move tile to the settle node // If successful, check if its closer than the current closestNode if (MAContRef.Pathing(moveTile, settleNode, CharacterType.Enemy)) { // It its closer, its the new closestNode if (closestF > settleNode.F) { closestNode = moveTile; closestF = settleNode.F; } } } return(closestNode); } }
/// <summary> /// Finds and returns the tile this enemy should move to. /// Find the closest tile they can attack 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 ally node with an attackable node Node closestAllyNode = null; int closestAllyF = int.MaxValue; Node closestAttackNode = null; int closestAttackF = int.MaxValue; // Iterate over each ally to find the closest foreach (Transform charTrans in GetAllyParent()) { // Get the node that character is on Node charNode = MAContRef.GetNodeByWorldPosition(charTrans.position); // Path to that ally 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 ally if (closestAllyF > charNode.F) { int charFVal = charNode.F; //Debug.Log("It was closer in distance"); // 2) Get the closest node this enemy could attack that ally from // We know that is enemy is closer in walking distance, but we don't know if they have any openings to attack // So we test to see if we can find any openings to attack // Get the potential nodes to attack from List <Node> potAttackNodes = 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 potAttackNodes) { //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 (closestAttackF > curAdjNode.F) { //Debug.Log("It was closer and could be attacked"); // It is the new closest enemy node closestAllyNode = charNode; closestAllyF = charFVal; // It is the new closest attack node closestAttackNode = curAdjNode; closestAttackF = curAdjNode.F; } } } } } } // If there is no closest attack from node, return the current Node if (closestAttackNode == null) { //Debug.Log("There was no closest Ally with an opening to attack"); return(StandingNode); } //Debug.Log("The closest ally is at " + closestAllyNode.Position); // This short find a tile to move to replaced the other way, which was faster, but much more complex // Short cut. If the closest attack node is one of the moveTiles, just return it // Iterate over the possible tiles to move to foreach (Node moveTile in MARef.MoveTiles) { // If its a part of the movetiles if (moveTile == closestAttackNode) { return(closestAttackNode); } } // If the shortcut didn't work do it the long way Node closestNode = StandingNode; int closestF = int.MaxValue; // 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, closestAttackNode, CharacterType.Enemy)) { // It its closer, its the new closestNode if (closestF > closestAttackNode.F) { closestNode = moveTile; closestF = closestAttackNode.F; } } } // Its the endtile return(closestNode); }
/// <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); }