VanRtkDbg/Assets/Scripts/Unit.cs

410 lines
12 KiB
C#

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 baseData;
[SerializeField]
private int basicAttack;
private int finalAttack;
[SerializeField]
private int currentDefense;
[SerializeField]
private int basicMaxDefense;
private int finalMaxDefense;
[SerializeField]
private List<CardTag> cardTags;
[SerializeField]
private List<UnitClass> unitClasses;
[SerializeField]
private List<Ability> abilities;
[SerializeField]
private int meleeAttackRange = 1;
public int MeleeAttackRange
{
get { return meleeAttackRange; }
set { meleeAttackRange = value; }
}
[SerializeField]
private int rangedAttackRange = 1;
public int RangedAttackRange
{
get { return rangedAttackRange; }
set { rangedAttackRange = value; }
}
[SerializeField]
private int movement = 1;
public int Movement
{
get { return movement; }
set { movement = value; }
}
[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;
public bool isUnitAlive()
{
return currentDefense > 0;
}
// Start is called before the first frame update
void Start()
{
cellMap = FindObjectOfType<CellMap>();
transform.position = standingCell.transform.position;
transform.position = new Vector3(transform.position.x, transform.position.y, -1);
standingCell.standingUnit = this;
basicAttack = baseData.attack;
basicMaxDefense = baseData.defense;
currentDefense = basicMaxDefense;
cardTags = baseData.tags.ToList();
unitClasses = baseData.unitClasses.ToList();
foreach (var unitClass in unitClasses)
{
unitClass.ApplyClassSpecilization(this);
}
modelArt.GetComponent<SpriteRenderer>().sprite = baseData.artwork;
var camps = FindObjectsOfType<Camp>();
foreach (var camp in camps)
{
if (camp.side == side)
{
allyCamp = camp;
}
else
{
enemyCamp = camp;
}
}
}
void UpdateAnimation()
{
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.");
}
}
}
void UpdateText()
{
attackText.GetComponent<TextMeshProUGUI>().text = finalAttack.ToString();
defenseText.GetComponent<TextMeshProUGUI>().text = currentDefense.ToString();
}
// Update is called once per frame
void Update()
{
UpdateAnimation();
finalAttack = basicAttack; // For now.
UpdateText();
}
public void MoveAndAttack()
{
MoveAction();
AttackAction();
}
public void MoveAction()
{
if (walkingToDestination)
{
return;
}
foreach (var tag in cardTags)
{
if (tag.name == "Archer")
{
for (int i = 0; i < meleeAttackRange; ++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 cardTags)
{
if (tag.name == "Archer")
{
// Archer can't dog fight.
return;
}
}
}
List<Unit> unitsInRange = new List<Unit>();
for (int i = 0; i < meleeAttackRange; ++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<Unit>();
}
else
{
unitsInRange = unitsInRange.OrderByDescending(x => x.standingCell.xPos).ToList<Unit>();
}
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<UnitManager>().handleDiedUnit(unit);
//Debug.Log("Defeat Enemy");
}
break; // Most of units can only attack one target.
}
}
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;
}
}