using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Assertions; using TMPro; public enum CurrentCommand { defend, moveForward, retreat } // Left is Player, Enemy is right. public enum Side { left = 1, right = -1 } public class Unit : MonoBehaviour { public string unitName; public CardData cardData; [SerializeField] private int basicAttack; private int finalAttack; [SerializeField] private int currentDefense; [SerializeField] private int basicMaxDefense; private int finalMaxDefense; [SerializeField] private CardTag[] cardTags; [SerializeField] private int attackRange = 1; [SerializeField] private int movement = 1; [SerializeField] private CurrentCommand currentCommand; public Cell standingCell; [SerializeField] private Cell destinationCell; private CellMap cellMap; public Side side; public Transform modelArt; public Transform attackText; public Transform defenseText; public bool walkingToDestination = false; Camp allyCamp; Camp enemyCamp; // Start is called before the first frame update void Start() { cellMap = FindObjectOfType(); transform.position = standingCell.transform.position; transform.position = new Vector3(transform.position.x, transform.position.y, -1); standingCell.standingUnit = this; basicAttack = cardData.attack; basicMaxDefense = cardData.defense; currentDefense = basicMaxDefense; cardTags = cardData.cardTags; foreach (var tag in cardData.cardTags) { if (tag.name == "Archer") { attackRange += 2; } else if (tag.name == "Cavalry") { movement += 1; } } modelArt.GetComponent().sprite = cardData.artwork; var camps = FindObjectsOfType(); foreach (var camp in camps) { if (camp.side == side) { allyCamp = camp; } else { enemyCamp = camp; } } } // Update is called once per frame void Update() { if (walkingToDestination && destinationCell && transform.position != destinationCell.transform.position) { Vector3 moveVec = destinationCell.transform.position - transform.position; transform.position = new Vector3(transform.position.x + moveVec.x * 5.0f * Time.deltaTime, transform.position.y + moveVec.y * 5.0f * Time.deltaTime, -1); //Debug.Log("Manitude: " + moveVec.magnitude); if ((Mathf.Approximately(transform.position.x, destinationCell.transform.position.x) && Mathf.Approximately(transform.position.y, destinationCell.transform.position.y)) || moveVec.magnitude <= 1) { walkingToDestination = false; transform.position = new Vector3(destinationCell.transform.position.x, destinationCell.transform.position.y, -1); destinationCell = null; //Debug.Log("Arrived."); } } finalAttack = basicAttack; // For now. attackText.GetComponent().text = finalAttack.ToString(); defenseText.GetComponent().text = currentDefense.ToString(); } public void MoveAndAttack() { MoveAction(); AttackAction(); } public void MoveAction() { if (walkingToDestination) { return; } foreach (var tag in cardData.cardTags) { if (tag.name == "Archer") { for (int i = 0; i < attackRange; ++i) { int attackXPos = standingCell.xPos + (i + 1) * (int)side; if (attackXPos >= cellMap.column || attackXPos < 0) { // Attack Camp currentCommand = CurrentCommand.defend; break; } Cell nextCellInRange = cellMap.GetCell(attackXPos, standingCell.yPos); Unit targetUnit = nextCellInRange.standingUnit; if (targetUnit) { if (targetUnit.side != side) { // Add units to attack list. currentCommand = CurrentCommand.defend; break; } } currentCommand = CurrentCommand.moveForward; } break; } } //Debug.Log("Call MoveAction()."); switch (currentCommand) { case CurrentCommand.defend: break; case CurrentCommand.moveForward: //Debug.Log("Try Move Forward."); for (int i = 0; i < movement; i++) { if (checkDestinationCellEmpty()) { // Attack() //Debug.Log("Start Moving."); MoveToCell(destinationCell); walkingToDestination = true; } else { //Debug.Log("Can't Move."); // Check the unit is facing the camp or unit. if (destinationCell) { // Check the unit is Allie or Enemy. if (destinationCell.standingUnit.side == side) { // Check the Allie is swappable or not. if (!inDogFight(destinationCell.standingUnit)) { //standingCell = cell; //cell.standingUnit = this; destinationCell.standingUnit.walkingToDestination = true; standingCell.standingUnit = destinationCell.standingUnit; standingCell.standingUnit.standingCell = standingCell; standingCell.standingUnit.destinationCell = standingCell; standingCell = destinationCell; destinationCell.standingUnit = this; walkingToDestination = true; } } else { // Can't move to cell this is standed by enemy. destinationCell = standingCell; break; } } else { // Facing the camp. break; } destinationCell = standingCell; } } break; case CurrentCommand.retreat: break; default: break; } } public void AttackAction() { // Check Attack Range if (inDogFight(this)) { foreach (var tag in cardData.cardTags) { if (tag.name == "Archer") { // Archer can't dog fight. return; } } } List unitsInRange = new List(); for (int i = 0; i < attackRange; ++i) { int attackXPos = standingCell.xPos + (i+1) * (int)side; if (attackXPos >= cellMap.column || attackXPos < 0) { // Attack Camp enemyCamp.TakeDamage(finalAttack); return; } Cell nextCellInRange = cellMap.GetCell(attackXPos, standingCell.yPos); Unit targetUnit = nextCellInRange.standingUnit; if (targetUnit) { if (targetUnit.side != side) { // Add units to attack list. unitsInRange.Add(targetUnit); } else { // It is allies. We don't attack it unless we are under some debuff. } } else { // Nothing to attack. //Debug.Log("No unit to attack."); } } if (side == Side.left) { unitsInRange = unitsInRange.OrderBy(x => x.standingCell.xPos).ToList(); } else { unitsInRange = unitsInRange.OrderByDescending(x => x.standingCell.xPos).ToList(); } for (int i = 0; i < unitsInRange.Count; i++) { //Debug.Log(unitsInRange[i].unitName + ": " + unitsInRange[i].standingCell.xPos + " , " + unitsInRange[i].standingCell.yPos); // Do attack //Debug.Log("Attack!"); unitsInRange[i].currentDefense -= finalAttack; if (unitsInRange[i].currentDefense <= 0) { unitsInRange[i].standingCell.standingUnit = null; unitsInRange[i].gameObject.SetActive(false); // For now Unit unit = unitsInRange[i]; FindObjectOfType().handleDiedUnit(unit); //Debug.Log("Defeat Enemy"); } break; // Most of units can only attack one target. } } public bool isUnitAlive() { return currentDefense > 0; } bool checkDestinationCellEmpty(bool retreat = false) { int currentXPos = standingCell.xPos; int movePath = 0; if (retreat) { movePath = 1 * -(int)side; } else { movePath = 1 * (int)side; } int destinationXPos = standingCell.xPos + movePath; // Mean the destination cell is the Camp. if (!checkPosInMap(destinationXPos)) { return false; } destinationCell = cellMap.GetCell(destinationXPos, standingCell.yPos); if (destinationCell.standingUnit == null) { return true; } else { // Check privous cell is standable if we have more than 1 movement ability. return false; } } void MoveToCell(Cell cell) { Assert.IsTrue(destinationCell.standingUnit == null, "Trying to move a cell that is already be standing by another unit."); standingCell.standingUnit = null; standingCell = cell; cell.standingUnit = this; } // Check the allies is near by an enemy or not. bool inDogFight(Unit unit) { int checkPos = unit.standingCell.xPos + (int)side * 1; if (!checkPosInMap(checkPos)) { return false; } var checkCell = cellMap.GetCell(checkPos, standingCell.yPos); if (checkCell.standingUnit && checkCell.standingUnit.side != side) { return true; } return false; } bool checkPosInMap(int pos) { return pos >= 0 && pos < cellMap.column; } }