Created
May 10, 2016 20:06
-
-
Save IronMonk-UK/49990ab91fc67a28da42dfca81c275fb to your computer and use it in GitHub Desktop.
Classes changed in the latest implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
/* The _Class class is used currently to assign stats to units. When a unit is instantiated, one of the functions below is called, setting the stats for that unit. | |
* I have been recommended to create a class for every unit class in game. At this time, until I have implemented AI further, I will be sticking to this class for unit classes. */ | |
public class _Class : MonoBehaviour { | |
public static _Class cInstance; | |
public static void Fighter(UserUnit u){ | |
u._class = "Fighter"; | |
u.totalHealth = 32; | |
u.strength = 3; | |
u.defence = 1; | |
u.accuracy = .7f; | |
u.damageRollSides = 8; | |
u.moveLimit = 6; | |
u.axe = true; | |
} | |
public static void Knight(UserUnit u){ | |
u._class = "Knight"; | |
u.totalHealth = 28; | |
u.strength = 2; | |
u.defence = 2; | |
u.accuracy = .8f; | |
u.damageRollSides = 7; | |
u.moveLimit = 8; | |
u.spear = true; | |
} | |
public static void Mercenary(UserUnit u){ | |
u._class = "Mercenary"; | |
u.totalHealth = 23; | |
u.strength = 2; | |
u.defence = 1; | |
u.accuracy = .9f; | |
u.damageRollSides = 6; | |
u.moveLimit = 6; | |
u.sword = true; | |
} | |
public static void Thug(AIUnit a) { | |
a._class = "Thug"; | |
a.totalHealth = 15; | |
a.strength = 1; | |
a.defence = 1; | |
a.accuracy = .7f; | |
a.damageRollSides = 5; | |
a.moveLimit = 6; | |
a.sword = true; | |
} | |
public static void Mauruder(AIUnit a) { | |
a._class = "Mauruder"; | |
a.totalHealth = 19; | |
a.strength = 1; | |
a.defence = 3; | |
a.accuracy = .8f; | |
a.damageRollSides = 6; | |
a.moveLimit = 8; | |
a.spear = true; | |
} | |
public static void Barbarian(AIUnit a) { | |
a._class = "Barbarian"; | |
a.totalHealth = 23; | |
a.strength = 3; | |
a.defence = 0; | |
a.accuracy = .6f; | |
a.damageRollSides = 8; | |
a.moveLimit = 6; | |
a.spear = true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class AIUnit : Unit { | |
GameManager gm; | |
Pathfinding path; | |
Grid grid; | |
Renderer rend; | |
List<UserUnit> unitsInRange = new List<UserUnit>(); | |
List<UserUnit> posWeapType = new List<UserUnit>(); | |
List<UserUnit> inRangeOfUnits = new List<UserUnit>(); | |
List<UserUnit> inRangeOfPos = new List<UserUnit>(); | |
Item healthVialToUse; | |
bool targetPicked; | |
bool inRangeTarget; | |
bool posWeapTarget; | |
bool noUnitsinRange; | |
bool healthChecked; | |
bool canUseVial; | |
bool cannotUseVial; | |
bool nothingInRange; | |
bool fleeing; | |
bool movedForward; | |
bool standingGround; | |
// Use this for initialization | |
void Awake () { | |
rend = GetComponent<Renderer>(); | |
gm = GameManager.gm; | |
path = gm.pathfinding; | |
grid = gm.grid; | |
} | |
// Update is called once per frame | |
void Update () { | |
if (gm.currentUnitIndex < gm.units.Count) { | |
if (gm.units[gm.currentUnitIndex] == this) { | |
rend.material.color = Color.green; | |
} else { | |
rend.material.color = Color.red; | |
} | |
// Ensures that booleans and lists are cleared after an AI units turn | |
if ((this != gm.units[gm.currentUnitIndex] && unitsInRange.Count > 0) || (this != gm.units[gm.currentUnitIndex] && noUnitsinRange)) { | |
unitsInRange.Clear(); | |
posWeapType.Clear(); | |
inRangeOfUnits.Clear(); | |
targetPicked = false; | |
inRangeTarget = false; | |
posWeapTarget = false; | |
noUnitsinRange = false; | |
healthChecked = false; | |
canUseVial = false; | |
cannotUseVial = false; | |
nothingInRange = false; | |
movedForward = false; | |
standingGround = false; | |
moving = false; | |
moved = false; | |
Debug.Log("List Cleared"); | |
} | |
} | |
if (currentHealth <= 0) { | |
transform.rotation = Quaternion.Euler(new Vector3(90, 0, 0)); | |
rend.material.color = Color.red; | |
gm.units.Remove(this); | |
} | |
} | |
public override void turnUpdate(){ | |
// If the list of user units is empty, a method is run to search for them | |
if(unitsInRange.Count == 0 && !noUnitsinRange) { | |
Debug.Log("In Range Check"); | |
inRange(); | |
} | |
// If there are no units in range, check if this AI unit is in range of any User units | |
if (unitsInRange.Count == 0 && noUnitsinRange && inRangeOfUnits.Count == 0) { | |
Debug.Log("In Range Of Check"); | |
inRangeOf(); | |
} | |
// If there is one or more User units in range, or none, and health has not been checked, the AI checks its health | |
// This is done so the health check only activates if the AI is not in range to attack any User units | |
if ((inRangeOfUnits.Count >= 1 && !healthChecked) || (nothingInRange && !healthChecked)) { | |
Debug.Log("Health Check"); | |
checkHealth(); | |
} | |
// If health has been checked, and there are no units in range, the AI checks if it is safe to move towards a User unit | |
if(healthChecked && nothingInRange) { | |
Debug.Log("Nothing in Range. Can use Vial"); | |
moveForward(); | |
} | |
// If the AI has moved forward, or is standing their ground, the useVial method is run | |
if((movedForward && moved) || standingGround) { | |
useVial(); | |
} | |
// If the AI is in range of a User unit that can attack it positively, it moves away from it, prioritising a positive attacker over any other User units in range | |
if (healthChecked && inRangeOfPos.Count >= 1 && !moving && !fleeing) { | |
Debug.Log("Move from Positive"); | |
moveFromPos(); | |
// else if the AI is in range of only a basic User unit that can attack it, it flees from them | |
} else if (healthChecked && inRangeOfUnits.Count >= 1 && inRangeOfPos.Count == 0 && !moving && !fleeing) { | |
Debug.Log("Moving from non-Positive"); | |
moveFromRange(); | |
} | |
// If it has moved out of range of a User unit, the useVial method is run | |
if ((healthChecked && inRangeOfPos.Count >= 1 && moved) || (healthChecked && inRangeOfUnits.Count >= 1 && inRangeOfPos.Count == 0 && moved)) { | |
Debug.Log("Use vial after moving from Positive"); | |
useVial(); | |
} | |
// If there is a user unit who the AI can positively attack in range, the corresponding method is run | |
// Otherwise, the AI locates an in range enemy, and runs the corresponding method | |
if (posWeapType.Count >= 1 && !targetPicked && !moving) { | |
Debug.Log("Attack Positively"); | |
PosWeaponAttack(); | |
} else if (unitsInRange.Count >= 1 && !targetPicked && !moving && !posWeapTarget) { | |
Debug.Log("Attack in Range"); | |
InRangeAttack(); | |
} | |
// If the AI has moved up to the unit, and it is one that can be attacked positively, the attack method is called | |
// This is currently attacking the first in the list, should the list have multiple user units, they will be ignored at this point | |
// Otherwise, if the AI has moved to the unit, and it is simply in range, the method is called | |
// These two if statements were made so the correct unit could be directly attacked. I shall attempt to alter this so the AI makes further decisions on who to attack | |
// if there are multiple normal or positive weapon units in range. | |
if (moved && posWeapTarget) { | |
gm.attackWithCurrentPlayer(posWeapType[0].currentTile); | |
} else if (moved && inRangeTarget && !posWeapTarget) { | |
gm.attackWithCurrentPlayer(unitsInRange[0].currentTile); | |
} | |
base.turnUpdate (); | |
} | |
public void inRange() { | |
Debug.Log("Checking in range"); | |
// Checks every user unit on the field | |
foreach (UserUnit u in gm.userUnits) { | |
Debug.Log(u._name); | |
// The path target moves to the tile of the unit | |
path.target.transform.position = u.currentTile._pos; | |
// The pathfinder draws the quickest path to the target | |
path.FindPath(); | |
// As the AI does not need to be on the same tile to attack, but an adjacent tile, the total tiles minus one is compared against the AIs movement limit | |
if(grid.path.Count - 1 <= moveLimit) { | |
// If the unit is in range, they are added to the list of units in range | |
unitsInRange.Add(u); | |
// Checks the AIs positive weapon type against the user units weapon | |
if (equippedWeapon.posType == u.equippedWeapon.weaponType) { | |
// If the same, that unit is added to the positive weapon type list | |
/* This saves having to run a second foreach loop to determine which user units have a weapon type the AI is good against, should there be | |
* multiple units in range. */ | |
posWeapType.Add(u); | |
} | |
} | |
} | |
// Reset the target position to the AI units tile | |
path.target.transform.position = currentTile._pos; | |
// Ensures the path is redrawn correctly | |
path.FindPath(); | |
if (unitsInRange.Count == 0) { | |
noUnitsinRange = true; | |
} | |
Debug.Log(unitsInRange.Count); | |
} | |
// This method runs to see if the AI unit is in range of any User units | |
public void inRangeOf() { | |
// Going through each User unit in the userUnits list | |
foreach (UserUnit u in gm.userUnits) { | |
// The path target is placed on their position, and the path is re-drawn | |
path.target.transform.position = u.currentTile._pos; | |
path.FindPath(); | |
// If the path length - 1 (As the User unit does not need to be ON the AI unit, only next to it) is less than the User units move limit | |
if(grid.path.Count - 1 <= u.moveLimit) { | |
// The User unit is added to the list of units the AI unit is in range of | |
inRangeOfUnits.Add(u); | |
// If the User units weapon type equals the AIs weapons negative type (Meaning an attack on the AI from the user unit would be positive) | |
if(equippedWeapon.negType == u.equippedWeapon.weaponType) { | |
// They are also added to the list of in range positive attackers | |
inRangeOfPos.Add(u); | |
} | |
} | |
} | |
// The path target is then placed back on top of the current AI unit, and the path is re-drawn | |
path.target.transform.position = currentTile._pos; | |
path.FindPath(); | |
// If the AI is in range of no units, the nothingInRange boolean is set to true | |
if(unitsInRange.Count == 0 && inRangeOfUnits.Count == 0) { | |
nothingInRange = true; | |
} | |
} | |
// This method is run if an enemy is in the PosWeapType list | |
public void PosWeaponAttack() { | |
// The target is set to the first index of the list | |
path.target.transform.position = posWeapType[0].currentTile._pos; | |
// The path is redrawn | |
path.FindPath(); | |
// As a target has been chosen, the bool turns true | |
targetPicked = true; | |
// As the target has a weapon type the AI can positively attack, the posWeapTarget bool is set to true | |
posWeapTarget = true; | |
if (grid.path.Count - 1 <= moveLimit) { | |
// Creates a temporary Vector3 | |
Vector3 backOne = new Vector3(0, 0, 0); | |
// If the path count is only one, meaning the unit is one tile away | |
if (grid.path.Count == 1) { | |
Debug.Log("1"); | |
// moved is set to true, as the AI will not actually have to move | |
moved = true; | |
} | |
// Else if the path count is 2 | |
else if (grid.path.Count == 2) { | |
Debug.Log("2"); | |
// backOne is set to the first position on the path. As the unit is two tiles away, there is only one tile between them; the first in the path list | |
backOne = grid.path[0].tile._pos; | |
// The target is set to the tile in front of the unit and AI | |
path.target.transform.position = backOne; | |
// Moving is set to true, as the unit is now moving | |
moving = true; | |
// The path is redrawn | |
path.FindPath(); | |
// The movement Coroutine is started | |
gm.moveCurrentPlayer(); | |
} | |
// Else if the path count is 3 or greater | |
else if (grid.path.Count >= 3) { | |
Debug.Log("3+"); | |
/* To get the tile in front of the unit, I take the grid path count, and take away two. One, to account for the fact the count != the index. By removing | |
* one, I bring the given number to match the array index. I remove one further, to take us back one tile from the unit. */ | |
backOne = grid.path[grid.path.Count - 2].tile._pos; | |
Debug.Log("BackOne : " + backOne); | |
// The same sequence sa in the above else if is run | |
path.target.transform.position = backOne; | |
moving = true; | |
path.FindPath(); | |
gm.moveCurrentPlayer(); | |
} | |
} | |
} | |
// The InRangeAttack functions almost identical to the PosWeaponAttack, apart from the assignment of the initial path target. | |
// I realise this could be potentially be made more efficient, and will be looked at once the entire decision tree has been implemented | |
public void InRangeAttack() { | |
path.target.transform.position = unitsInRange[0].currentTile._pos; | |
path.FindPath(); | |
targetPicked = true; | |
inRangeTarget = true; | |
if (grid.path.Count - 1 <= moveLimit) { | |
Vector3 backOne = new Vector3(0, 0, 0); | |
if (grid.path.Count >= 3) { | |
backOne = grid.path[grid.path.Count - 2].tile._pos; | |
path.target.transform.position = backOne; | |
moving = true; | |
path.FindPath(); | |
gm.moveCurrentPlayer(); | |
} else if (grid.path.Count == 2) { | |
backOne = grid.path[0].tile._pos; | |
path.target.transform.position = backOne; | |
moving = true; | |
path.FindPath(); | |
gm.moveCurrentPlayer(); | |
} else if (grid.path.Count == 1) { | |
moved = true; | |
} | |
} | |
} | |
// The moveFromPos function works out which direction the AI wants to retreat in, and how far, from a positive User unit | |
public void moveFromPos() { | |
// The path target is set to the first positive User unit in the list, and the path re-drawn | |
path.target.transform.position = inRangeOfPos[0].currentTile._pos; | |
path.FindPath(); | |
// The difference between the User units move limit, and the path length, is worked out | |
// The move limit of the User unit takes away the path length - 1, as the User units path will start one tile in front of itself | |
// 1 is added, so that the unit will always move one tile further back than the User units move limit | |
// Example: User Knight has move limit 8. AI Barbarian is 8 tiles away, too far to attack | |
// (Move limit) 8 - (7) (The path length to the User unit, - 1) + 1 | |
// 8 - 7 + 1 = 2 | |
// This will result in the AI Barbarian moving back 2 tiles (10 tiles total from the User unit), leaving a tile between how far the User Knight can move, | |
// And how far away the AI Barbarian is | |
int difference = (inRangeOfPos[0].moveLimit - (grid.path.Count - 1) + 1); | |
Debug.Log("Difference : " + difference); | |
// A set of if statements are run, comparing the position of the tile in front of the User unit, to the following tile in the list | |
// Based on the difference of grid co-ordinates, the AI will determine which way to move from the User unit | |
if (grid.path[1].gridX == grid.path[0].gridX + 1) { | |
Debug.Log("Path goes right"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX - difference, currentTile.node.gridY].tile._pos; | |
} else if (grid.path[1].gridX == grid.path[0].gridX - 1) { | |
Debug.Log("Path goes left"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX + difference, currentTile.node.gridY].tile._pos; | |
} else if (grid.path[1].gridY == grid.path[0].gridY + 1) { | |
Debug.Log("Path goes up"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX, currentTile.node.gridY - difference].tile._pos; | |
} else if (grid.path[1].gridY == grid.path[0].gridY - 1) { | |
Debug.Log("Path goes down"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX, currentTile.node.gridY + difference].tile._pos; | |
} | |
// The path is re-drawn once re-positioned, the fleeing bool is set to true, and the unit moves | |
path.FindPath(); | |
fleeing = true; | |
gm.moveCurrentPlayer(); | |
} | |
// Much like the positive and regular attack methods above, moveFromRange only differs in the list it picks the User unit from | |
public void moveFromRange() { | |
path.target.transform.position = inRangeOfUnits[0].currentTile._pos; | |
path.FindPath(); | |
int difference = (inRangeOfUnits[0].moveLimit - (grid.path.Count - 1)) + 1; | |
Debug.Log("Difference : " + difference); | |
if (grid.path[1].gridX == grid.path[0].gridX + 1) { | |
Debug.Log("Path goes right"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX - difference, currentTile.node.gridY].tile._pos; | |
} else if (grid.path[1].gridX == grid.path[0].gridX - 1) { | |
Debug.Log("Path goes left"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX + difference, currentTile.node.gridY].tile._pos; | |
} else if (grid.path[1].gridY == grid.path[0].gridY + 1) { | |
Debug.Log("Path goes up"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX, currentTile.node.gridY - difference].tile._pos; | |
} else if (grid.path[1].gridY == grid.path[0].gridY - 1) { | |
Debug.Log("Path goes down"); | |
path.target.transform.position = grid.grid[currentTile.node.gridX, currentTile.node.gridY + difference].tile._pos; | |
} | |
path.FindPath(); | |
fleeing = true; | |
gm.moveCurrentPlayer(); | |
} | |
// This method checks to see if the AI unit can/needs to use a health vial | |
public void checkHealth() { | |
// If the current health is 10 or less than the total health | |
// Or the total health is less than 10, and the current health is 2 or less than the total health | |
if((currentHealth <= totalHealth - 10) || (totalHealth <= 10 && currentHealth <= totalHealth - 2)) | |
{ | |
// The inventory of the AI unit is checked | |
foreach (Item i in inventory) { | |
// If a health vial is found, canUseVial is set to true, and that vial is set to the healthVialToUse, then breaks out the loop | |
if (i.itemType == Item.ItemType.Tool) { | |
canUseVial = true; | |
healthVialToUse = i; | |
break; | |
} | |
} | |
} | |
// If a health vial isn't found, or the AIs current health is high enough, cannotUseVial is set to true | |
if (!canUseVial) { | |
cannotUseVial = true; | |
} | |
// The healthChecked bool is set to true regardless, informing the AI that it has checked its health | |
healthChecked = true; | |
} | |
// If there are no User units the AI can reach, and no units can reach the AI, it will attempt to move forward | |
void moveForward() { | |
int i = 0; | |
UserUnit target = null; | |
// Checking every user unit | |
foreach (UserUnit u in gm.userUnits) { | |
// The path target is positioned on the User unit, and the path re-drawn | |
path.target.transform.position = u.currentTile._pos; | |
path.FindPath(); | |
// Temporary int j takes the path length needed to be in front of a User unit | |
int j = grid.path.Count - 1; | |
// If j is less than temp int i | |
if(j < i) { | |
// j is set to i | |
i = j; | |
// The User unit is set to the target | |
target = u; | |
} | |
} | |
// If i minus the AIs move limit is less than the target User units move limit, plus 1 | |
if(i - moveLimit > target.moveLimit + 1) { | |
// The AI moves forward towards that User unit | |
moving = true; | |
gm.moveCurrentPlayer(); | |
movedForward = true; | |
} else { | |
// Else they stand their ground on the current tile | |
standingGround = true; | |
} | |
} | |
// This method is run after an AI unit has fled, either allowing them to use a vial, or ending the turn | |
void useVial() { | |
// If the AI can use a vial | |
if (canUseVial) { | |
// The heal function on the health vial is used | |
healthVialToUse._heal(this); | |
// It is removed from the inventory | |
inventory.Remove(healthVialToUse); | |
// The healthVialToUse is set to null | |
healthVialToUse = null; | |
Debug.Log("Vial was used"); | |
// The turn ends | |
gm.EndTurn(); | |
// else if the AI cannot use a vial | |
} else if (cannotUseVial) { | |
Debug.Log("Vial not required / Available"); | |
// The turn ends | |
gm.nextTurn(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.UI; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class GameManager : MonoBehaviour | |
{ | |
public static GameManager gm; | |
public GameObject tilePrefab; | |
public GameObject userUnitPrefab; | |
public GameObject AIUnitPrefab; | |
public Text _name; | |
public Text _class; | |
public Text _health; | |
public Text _strength; | |
public Text _defence; | |
public Text _accuracy; | |
public Text _eName; | |
public Text _eClass; | |
public Text _eHealth; | |
public Text _eStrength; | |
public Text _eDefence; | |
public Text _eAccuracy; | |
public Button inv1; | |
public Text _inv1; | |
public Button inv2; | |
public Text _inv2; | |
public Button inv3; | |
public Text _inv3; | |
public Button inv4; | |
public Text _inv4; | |
public Button inv5; | |
public Text _inv5; | |
public List<Button> inv = new List<Button>(); | |
public Text announcer; | |
public int mapSize; | |
public bool startMove; | |
bool supportAttack; | |
bool posHit; | |
bool posSupHit; | |
bool negHit; | |
bool negSupHit; | |
bool hit; | |
bool supHit; | |
public bool unitMoving; | |
public List<List<Tile>> map = new List<List<Tile>>(); | |
public List<Unit> units = new List<Unit>(); | |
public List<Unit> userUnits = new List<Unit>(); | |
public List<Unit> aiUnits = new List<Unit>(); | |
public List<Vector2> moveTiles = new List<Vector2>(); | |
[Header("Manually Change Starting Positions")] | |
public List<Vector2> startingTiles = new List<Vector2>(); | |
public Grid grid; | |
public Pathfinding pathfinding; | |
public int currentUnitIndex; | |
public bool unitsPositioned; | |
Tile targetTile; | |
void Awake() | |
{ | |
// Makes the instance variable the current GameManager class | |
gm = this; | |
grid = GetComponent<Grid>(); | |
pathfinding = GetComponent<Pathfinding>(); | |
//EnemyStatsDown (); | |
} | |
void Start() | |
{ | |
// Runs the generateMap function on start | |
//generateMap (); | |
// Runs the generatePlayers function on start | |
generateUnits(); | |
currentUnitIndex = 0; | |
//announcer.text = ""; | |
} | |
void Update() | |
{ | |
if (currentUnitIndex >= units.Count) | |
{ | |
currentUnitIndex = 0; | |
pathfinding.target.transform.position = units[currentUnitIndex].currentTile._pos; | |
pathfinding.FindPath(); | |
} | |
// The units starting grid positions can now manually be set via the inspector, making debugging and testing much quicker | |
if (!unitsPositioned) | |
{ | |
for(int i = 0; i < units.Count; i++) { | |
units[i].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[i].x), Mathf.RoundToInt(startingTiles[i].y)].tile._pos; | |
units[i].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[i].x), Mathf.RoundToInt(startingTiles[i].y)].tile; | |
} | |
/*units[0].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[0].x), Mathf.RoundToInt(startingTiles[0].y)].tile._pos; | |
units[0].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[0].x), Mathf.RoundToInt(startingTiles[0].y)].tile; | |
units[1].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[1].x), Mathf.RoundToInt(startingTiles[1].y)].tile._pos; | |
units[1].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[1].x), Mathf.RoundToInt(startingTiles[1].y)].tile; | |
units[2].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[2].x), Mathf.RoundToInt(startingTiles[2].y)].tile._pos; | |
units[2].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[2].x), Mathf.RoundToInt(startingTiles[2].y)].tile; | |
units[3].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[3].x), Mathf.RoundToInt(startingTiles[3].y)].tile._pos; | |
units[3].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[3].x), Mathf.RoundToInt(startingTiles[3].y)].tile; | |
units[4].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[4].x), Mathf.RoundToInt(startingTiles[4].y)].tile._pos; | |
units[4].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[4].x), Mathf.RoundToInt(startingTiles[4].y)].tile; | |
units[5].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[5].x), Mathf.RoundToInt(startingTiles[5].y)].tile._pos; | |
units[5].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[5].x), Mathf.RoundToInt(startingTiles[5].y)].tile; | |
units[6].transform.position = grid.grid[Mathf.RoundToInt(startingTiles[6].x), Mathf.RoundToInt(startingTiles[6].y)].tile._pos; | |
units[6].currentTile = grid.grid[Mathf.RoundToInt(startingTiles[6].x), Mathf.RoundToInt(startingTiles[6].y)].tile;*/ | |
unitsPositioned = true; | |
pathfinding.target.transform.position = units[currentUnitIndex].currentTile._pos; | |
} | |
// This foreach loop is to ensure that a units grid position is always updating to its current grid position | |
foreach (Unit u in units) { | |
foreach (List<Tile> l in grid.map) { | |
foreach (Tile t in l) { | |
if (u.transform.position == new Vector3(t.transform.position.x, t.transform.position.y + 2, t.transform.position.z)) | |
u.gridPosition = t.gridPosition; | |
} | |
} | |
} | |
if (units[currentUnitIndex].inventory.Count == 1) { inventory1(); } | |
if (units[currentUnitIndex].inventory.Count == 2) { inventory2(); } | |
if (units[currentUnitIndex].inventory.Count == 3) { inventory3(); } | |
if (units[currentUnitIndex].inventory.Count == 4) { inventory4(); } | |
if (units[currentUnitIndex].inventory.Count == 5) { inventory5(); } | |
// This for loop runs to ensure that any usable item, such as the health vial | |
if (userUnits.Contains(units[currentUnitIndex])) { | |
for(int i = 0; i < units[currentUnitIndex].inventory.Count; i++) { | |
// if the item in inventory index i has the ItemType "Tool" | |
if (units[currentUnitIndex].inventory[i].itemType == Item.ItemType.Tool) { | |
// and if the Tool has the name "Health Vial" | |
if (units[currentUnitIndex].inventory[i].Name == "Health Vial") { | |
// create a temporary item variable, that is the inventory item with index i | |
Item item = units[currentUnitIndex].inventory[i]; | |
// Ensure that any previous listeners are removed from the button | |
inv[i].onClick.RemoveAllListeners(); | |
// Adds the item method _heal to the button's onClick | |
inv[i].onClick.AddListener(delegate { item._heal(units[currentUnitIndex]); }); | |
} | |
// If there is another weapon in the inventory that is not the currently equipped weapon | |
} else if (i != 0 && units[currentUnitIndex].inventory[i].itemType == Item.ItemType.Weapon) { | |
// A temporary int takes note of the inventory position | |
int j = i; | |
// The item being moved is put into a temp variable | |
Item itemToMove = units[currentUnitIndex].inventory[i]; | |
// As is the currently equipped item | |
Item currentItem = units[currentUnitIndex].inventory[0]; | |
// All previous listeners on that inventory position are removed | |
inv[j].onClick.RemoveAllListeners(); | |
// The moveItem method is attached to that button, taking in the item to move, the currently equipped item, and the inventory position | |
inv[j].onClick.AddListener(delegate { moveItem(itemToMove, currentItem, j); }); | |
} | |
} | |
} | |
/* Looks at which player in the player list is currently moving | |
* and constantly runs the turnUpdate function for them, as it is in the update function */ | |
if (units[currentUnitIndex].currentHealth > 0) | |
{ | |
units[currentUnitIndex].turnUpdate(); | |
} | |
else | |
{ | |
nextTurn(); | |
} | |
// Sets the UI text to show the current units stats | |
_name.text = units [currentUnitIndex]._name; | |
_class.text = units [currentUnitIndex]._class; | |
_health.text = units [currentUnitIndex].currentHealth.ToString() + " / " + units[currentUnitIndex].totalHealth.ToString(); | |
_strength.text = units [currentUnitIndex].strength.ToString(); | |
_defence.text = units [currentUnitIndex].defence.ToString(); | |
_accuracy.text = units [currentUnitIndex].accuracy.ToString(); | |
if (units[currentUnitIndex].moved) | |
units[currentUnitIndex].moving = false; | |
if (units[currentUnitIndex].moving == false) | |
{ | |
foreach (Vector3 v in moveTiles) | |
{ | |
foreach (List<Tile> l in map) | |
{ | |
foreach (Tile t in l) | |
{ | |
if (v == t.gridPosition) | |
{ | |
t.movingTile = false; | |
} | |
} | |
} | |
} | |
} | |
} | |
/* The nextTurn function determines which player is currently having their turn | |
* The current player index starts at 0, so must have +1 added to it when counting players so both start from 1. | |
* When the nextTurn function is run, if the player index + 1 is lower than the amount in the players list | |
* it will increase the index by one, causing the turnUpdate function above to start for a new player. | |
* If the index + 1 ends up equal to the amount of players in the list, it will start back to 0.*/ | |
/* While this is not my ideal turn system, I believe that as I progress with my research, it will help me form a base towards the operation of the AI | |
* As this is one potential way I could have enemy units moving one at a time as an index goes through a list of enemies */ | |
public void nextTurn() | |
{ | |
if (currentUnitIndex + 1 < units.Count) | |
{ | |
currentUnitIndex++; | |
pathfinding.target.transform.position = units[currentUnitIndex].currentTile._pos; | |
} | |
else | |
{ | |
currentUnitIndex = 0; | |
pathfinding.target.transform.position = units[currentUnitIndex].currentTile._pos; | |
} | |
} | |
/* The moveCurrentPlayer function sets the current player units moveDestination position as the destTile, as set when the player clicks on a tile through the Tile class | |
* OnMouseDown function. */ | |
/* The moveCurrentPlayer function now runs through an if statement to make sure the current unit has not already moved. If it has not, they will use one action, and move to the | |
* destTile. This function also sets the current units gridPosition to be that of the destTile's gridPosition, and then sets the moved boolean to true, | |
* so that unit cannot move again. */ | |
public void moveCurrentPlayer() | |
{ | |
targetTile = grid.path[grid.path.Count - 1].tile; | |
unitMoving = true; | |
if (units[currentUnitIndex].moved == false) | |
{ | |
int i = 0; | |
for (i = 0; (grid.path.Count <= units[currentUnitIndex].moveLimit && i < grid.path.Count) || (grid.path.Count >= units[currentUnitIndex].moveLimit && i < units[currentUnitIndex].moveLimit); i++) | |
{ | |
Debug.Log(grid.path[i].tile._pos); | |
units[currentUnitIndex].transform.position = grid.path[i].tile._pos; | |
units[currentUnitIndex].currentTile = grid.path[i].tile; | |
if (units[currentUnitIndex].currentTile == targetTile || i == units[currentUnitIndex].moveLimit - 1) | |
{ | |
Debug.Log("Done thing"); | |
units[currentUnitIndex].actions--; | |
units[currentUnitIndex].moved = true; | |
pathfinding.target.transform.position = units[currentUnitIndex].currentTile._pos; | |
pathfinding.FindPath(); | |
} | |
} | |
} | |
unitMoving = false; | |
} | |
public void attackWithCurrentPlayer(Tile destTile) | |
{ | |
// The attackWithCurrentPlayer function sets the rules of combat within the game, dealing with how the currently selected player can engage in combat. | |
/* The variable target is created first. A foreach loop then runs, looking for any unit that has the same gridPosition as the tile being selected, | |
* as rather than targetting a unit, the tile they are on is selected. If a unit is found, they are set as the target. */ | |
Unit target = null; | |
Unit support = null; | |
foreach (Unit u in units) | |
{ | |
if (u.gridPosition == destTile.gridPosition) | |
{ | |
target = u; | |
} | |
} | |
/* This if statement starts off by making sure that there is a target available. If so, the next if statement ensures that they are in a position that can be attacked by the | |
* current unit. If this returns true, an action is used by the current unit. A series of if statements are run after this, checking if the units class is weak against them, | |
* strong against them, or the same. At this point in time, units gain or lose accuracy based on this, and sets one of three booleans, based on the classes. | |
* THIS IS SUBJECT TO CHANGE. */ | |
if (target != null) | |
{ | |
/* So as not to create a giant line of specific gridPositions that can be attacked, I created 4 Vector3 variables, and implemented them into it. | |
* Each Vector3 represents a space above, below, left, or right, of the current units position */ | |
Vector3 up = new Vector2(target.gridPosition.x, target.gridPosition.y - 1); | |
Vector3 down = new Vector2(target.gridPosition.x, target.gridPosition.y + 1); | |
Vector3 left = new Vector2(target.gridPosition.x - 1, target.gridPosition.y); | |
Vector3 right = new Vector2(target.gridPosition.x + 1, target.gridPosition.y); | |
if (units[currentUnitIndex].gridPosition == up || units[currentUnitIndex].gridPosition == down || units[currentUnitIndex].gridPosition == left || units[currentUnitIndex].gridPosition == right) | |
{ | |
units[currentUnitIndex].actions--; | |
// Ensuring the Unique Support Mechanic (USM) only kicks in for User units | |
// The USM is a simple pincer attack. If another User unit is opposite the attacking unit, rather than only the attacking unit attacking, both they | |
// and the other, "supporting" unit attack in one turn | |
if (userUnits.Contains(units[currentUnitIndex])) { | |
// Checking every User unit | |
foreach (UserUnit u in userUnits) { | |
// If any User unit is opposite the attacking unit, supportAttack is turned true | |
if(units[currentUnitIndex].gridPosition == up && u.gridPosition == down) { | |
Debug.Log("Pincer Attack : Current unit down, Supporting unit up"); | |
supportAttack = true; | |
support = u; | |
} | |
if(units[currentUnitIndex].gridPosition == down && u.gridPosition == up) { | |
Debug.Log("Pincer Attack : Current unit up, Supporting unit down"); | |
supportAttack = true; | |
support = u; | |
} | |
if(units[currentUnitIndex].gridPosition == left && u.gridPosition == right) { | |
Debug.Log("Pincer Attack : Current unit left, Supporting unit right"); | |
supportAttack = true; | |
support = u; | |
} | |
if(units[currentUnitIndex].gridPosition == right && u.gridPosition == left) { | |
Debug.Log("Pincer Attack : Current unit right, Supporting unit left"); | |
supportAttack = true; | |
support = u; | |
} | |
} | |
} | |
// If supportAttack is true | |
if (supportAttack) { | |
// The support unit is run through the same checks as regularly attacking units | |
if (support.equippedWeapon.posType == target.equippedWeapon.weaponType) { | |
posSupHit = Random.Range(0.0f, 1.0f) <= (units[currentUnitIndex].accuracy + .2f); | |
} else if (support.equippedWeapon.negType == target.equippedWeapon.weaponType) { | |
negSupHit = Random.Range(0.0f, 1.0f) <= (units[currentUnitIndex].accuracy - .2f); | |
} else { | |
supHit = Random.Range(0.0f, 1.0f) <= units[currentUnitIndex].accuracy; | |
} | |
} | |
if (units[currentUnitIndex].equippedWeapon.posType == target.equippedWeapon.weaponType) { | |
posHit = Random.Range(0.0f, 1.0f) <= (units[currentUnitIndex].accuracy + .2f); | |
} else if (units[currentUnitIndex].equippedWeapon.negType == target.equippedWeapon.weaponType) { | |
negHit = Random.Range(0.0f, 1.0f) <= (units[currentUnitIndex].accuracy - .2f); | |
} else { | |
hit = Random.Range(0.0f, 1.0f) <= units[currentUnitIndex].accuracy; | |
} | |
/* This set of if statements breaks down the damage dealt to an opposing unit if the unit hits. Based on the boolean activated above, damage will be dealt with | |
* positive or negative modifiers, or no modifers. If the above hit does not return true, the attack simply misses. If the unit being attacked is not on an | |
* adjacent tile, the debug log will return stating the target is not available. */ | |
int damageAmount = 0; | |
int damageSupAmount = 0; | |
// Again confirming that supportingAttack is true | |
if (supportAttack) { | |
// If the supporting unit managed to land their hit, it is calculated in the same manner as regularly attacking units | |
if (posSupHit) { | |
damageSupAmount = (int)Mathf.Floor((support.strength + 1) + support.equippedWeapon.Damage - target.defence); | |
target.currentHealth -= damageSupAmount; | |
Debug.Log("Supporter " + support._name + " hit " + target._name + " effectively for " + damageSupAmount + " damage!"); | |
} else if (negSupHit) { | |
damageSupAmount = (int)Mathf.Floor((support.strength - 2) + support.equippedWeapon.Damage - target.defence); | |
target.currentHealth -= damageSupAmount; | |
Debug.Log("Supporter " + support._name + " hit " + target._name + " ineffectively for " + damageSupAmount + " damage!"); | |
} else if (supHit) { | |
damageSupAmount = (int)Mathf.Floor(support.strength + support.equippedWeapon.Damage - target.defence); | |
target.currentHealth -= damageSupAmount; | |
Debug.Log("Supporter " + support._name + " hit " + target._name + " for " + damageSupAmount + " damage!"); | |
} else { | |
Debug.Log("Supporter" + support._name + " missed " + target._name); | |
} | |
} | |
if (posHit) { | |
damageAmount = (int)Mathf.Floor((units[currentUnitIndex].strength + 1) + units[currentUnitIndex].equippedWeapon.Damage - target.defence); | |
target.currentHealth -= damageAmount; | |
announcer.text = (units[currentUnitIndex]._name + " hit " + target._name.ToString() + " effectively for " + damageAmount + " damage!"); | |
Debug.Log(units[currentUnitIndex]._name + " hit " + target._name + " effectively for " + damageAmount + " damage!"); | |
} else if (negHit) { | |
damageAmount = (int)Mathf.Floor((units[currentUnitIndex].strength - 2) + units[currentUnitIndex].equippedWeapon.Damage - target.defence); | |
target.currentHealth -= damageAmount; | |
announcer.text = (units[currentUnitIndex]._name + " hit " + target._name.ToString() + " ineffectively for " + damageAmount + " damage!"); | |
Debug.Log(units[currentUnitIndex]._name + " hit " + target._name + " ineffectively for " + damageAmount + " damage!"); | |
} else if (hit) { | |
damageAmount = (int)Mathf.Floor(units[currentUnitIndex].strength + units[currentUnitIndex].equippedWeapon.Damage - target.defence); | |
target.currentHealth -= damageAmount; | |
announcer.text = (units[currentUnitIndex]._name + " hit " + target._name.ToString() + " for " + damageAmount + " damage!"); | |
Debug.Log(units[currentUnitIndex]._name + " hit " + target._name + " for " + damageAmount + " damage!"); | |
} else { | |
Debug.Log("Attacker " + units[currentUnitIndex]._name + " missed " + target._name); | |
} | |
} | |
else | |
{ | |
Debug.Log("Target not available"); | |
} | |
} | |
supportAttack = false; | |
posHit = false; | |
posSupHit = false; | |
negHit = false; | |
negSupHit = false; | |
hit = false; | |
supHit = false; | |
} | |
void generateUnits() | |
{ | |
UserUnit unit; | |
unit = ((GameObject)Instantiate(userUnitPrefab, new Vector3(0 - Mathf.Floor(grid.worldSize.x / 2) + .5f, 1, -0 + Mathf.Floor(mapSize / 2) - .5f), Quaternion.Euler(new Vector3()))).GetComponent<UserUnit>(); | |
unit._name = "Bentley"; | |
_Class.Fighter(unit); | |
Items.sItems.IronAxe(unit); | |
Items.sItems.IronSpear(unit); | |
Items.sItems.IronSword(unit); | |
units.Add(unit); | |
userUnits.Add(unit); | |
unit = ((GameObject)Instantiate(userUnitPrefab, new Vector3((mapSize - 1) - Mathf.Floor(grid.worldSize.x / 2) + .5f, 1, -(grid.worldSize.y - 1) + Mathf.Floor(mapSize / 2) - .5f), Quaternion.Euler(new Vector3()))).GetComponent<UserUnit>(); | |
unit._name = "Harrison"; | |
_Class.Mercenary(unit); | |
Items.sItems.IronSword(unit); | |
units.Add(unit); | |
userUnits.Add(unit); | |
unit = ((GameObject)Instantiate(userUnitPrefab, new Vector3((mapSize - 1) - Mathf.Floor(grid.worldSize.x / 2) + .5f, 1, -(grid.worldSize.y - 1) + Mathf.Floor(mapSize / 2) - .5f), Quaternion.Euler(new Vector3()))).GetComponent<UserUnit>(); | |
unit._name = "Isaac"; | |
_Class.Mercenary(unit); | |
Items.sItems.IronSword(unit); | |
units.Add(unit); | |
userUnits.Add(unit); | |
unit = ((GameObject)Instantiate(userUnitPrefab, new Vector3(4 - Mathf.Floor(grid.worldSize.x / 2) + .5f, 1, -4 + Mathf.Floor(grid.worldSize.y / 2) - .5f), Quaternion.Euler(new Vector3()))).GetComponent<UserUnit>(); | |
unit._name = "Alexander"; | |
_Class.Knight(unit); | |
Items.sItems.IronSpear(unit); | |
units.Add(unit); | |
userUnits.Add(unit); | |
AIUnit aUnit; | |
aUnit = ((GameObject)Instantiate(AIUnitPrefab, new Vector3(0, 0, 0), Quaternion.Euler(new Vector3()))).GetComponent<AIUnit>(); | |
aUnit._name = "Tim"; | |
_Class.Thug(aUnit); | |
Items.sItems.IronSword(aUnit); | |
Items.sItems.healthVial(aUnit); | |
units.Add(aUnit); | |
aiUnits.Add(aUnit); | |
aUnit = ((GameObject)Instantiate(AIUnitPrefab, new Vector3(0, 0, 0), Quaternion.Euler(new Vector3()))).GetComponent<AIUnit>(); | |
aUnit._name = "Brick"; | |
_Class.Mauruder(aUnit); | |
Items.sItems.IronSpear(aUnit); | |
units.Add(aUnit); | |
aiUnits.Add(aUnit); | |
aUnit = ((GameObject)Instantiate(AIUnitPrefab, new Vector3(0, 0, 0), Quaternion.Euler(new Vector3()))).GetComponent<AIUnit>(); | |
aUnit._name = "Harry"; | |
_Class.Barbarian(aUnit); | |
Items.sItems.IronAxe(aUnit); | |
units.Add(aUnit); | |
aiUnits.Add(aUnit); | |
} | |
// These three functions are for use with the UI buttons, calling on the current unit and changing states within it, so it is either moving, attacking, or its turn has ended. | |
public void Move() | |
{ | |
if (units[currentUnitIndex].moving == false) | |
{ | |
units[currentUnitIndex].moving = true; | |
units[currentUnitIndex].attacking = false; | |
} | |
else | |
{ | |
units[currentUnitIndex].moving = false; | |
units[currentUnitIndex].attacking = false; | |
pathfinding.target.transform.position = units[currentUnitIndex].currentTile._pos; | |
} | |
} | |
public void Attack() | |
{ | |
if (units[currentUnitIndex].attacking == false) | |
{ | |
units[currentUnitIndex].attacking = true; | |
units[currentUnitIndex].moving = false; | |
} | |
else | |
{ | |
units[currentUnitIndex].moving = false; | |
units[currentUnitIndex].attacking = false; | |
} | |
} | |
public void EndTurn() | |
{ | |
if (!units[currentUnitIndex].moving && !aiUnits.Contains(units[currentUnitIndex])) { | |
units[currentUnitIndex].moving = false; | |
units[currentUnitIndex].attacking = false; | |
units[currentUnitIndex].actions = 2; | |
units[currentUnitIndex].moved = false; | |
nextTurn(); | |
} | |
} | |
public void EnemyStatsUp(){ | |
_eName.enabled = true; | |
_eClass.enabled = true; | |
_eHealth.enabled = true; | |
_eStrength.enabled = true; | |
_eDefence.enabled = true; | |
_eAccuracy.enabled = true; | |
} | |
public void EnemyStatsDown(){ | |
_eName.enabled = false; | |
_eClass.enabled = false; | |
_eHealth.enabled = false; | |
_eStrength.enabled = false; | |
_eDefence.enabled = false; | |
_eAccuracy.enabled = false; | |
} | |
// The following set of methods are designed to stop any errors occuring due to the inventory not being completely full, by ensuring blank spaces are set to null, | |
// depending on the amount of items in the inventory | |
public void inventory1() | |
{ | |
_inv1.text = units[currentUnitIndex].inventory[0].Name; | |
_inv2.text = null; | |
_inv3.text = null; | |
_inv4.text = null; | |
_inv5.text = null; | |
} | |
public void inventory2() | |
{ | |
_inv1.text = units[currentUnitIndex].inventory[0].Name; | |
_inv2.text = units[currentUnitIndex].inventory[1].Name; | |
_inv3.text = null; | |
_inv4.text = null; | |
_inv5.text = null; | |
} | |
public void inventory3() | |
{ | |
_inv1.text = units[currentUnitIndex].inventory[0].Name; | |
_inv2.text = units[currentUnitIndex].inventory[1].Name; | |
_inv3.text = units[currentUnitIndex].inventory[2].Name; | |
_inv4.text = null; | |
_inv5.text = null; | |
} | |
public void inventory4() | |
{ | |
_inv1.text = units[currentUnitIndex].inventory[0].Name; | |
_inv2.text = units[currentUnitIndex].inventory[1].Name; | |
_inv3.text = units[currentUnitIndex].inventory[2].Name; | |
_inv4.text = units[currentUnitIndex].inventory[3].Name; | |
_inv5.text = null; | |
} | |
public void inventory5() | |
{ | |
_inv1.text = units[currentUnitIndex].inventory[0].Name; | |
_inv2.text = units[currentUnitIndex].inventory[1].Name; | |
_inv3.text = units[currentUnitIndex].inventory[2].Name; | |
_inv4.text = units[currentUnitIndex].inventory[3].Name; | |
_inv5.text = units[currentUnitIndex].inventory[4].Name; | |
} | |
// This is the method run to change the currently equipped weapon | |
void moveItem(Item i, Item i2, int j) { | |
// If the unit is not moving or attacking | |
if(!units[currentUnitIndex].moving && !units[currentUnitIndex].attacking) { | |
// The current weapon is moved to the changing weapons inventory position | |
units[currentUnitIndex].inventory[j] = i2; | |
// And the changing weapon is positioned at the front of the array, making it the currently equipped weapon | |
units[currentUnitIndex].inventory[0] = i; | |
// A set of if statements then ensure the items are displayed correctly within the UI inventory | |
if (units[currentUnitIndex].inventory.Count == 1) { inventory1(); } | |
if (units[currentUnitIndex].inventory.Count == 2) { inventory2(); } | |
if (units[currentUnitIndex].inventory.Count == 3) { inventory3(); } | |
if (units[currentUnitIndex].inventory.Count == 4) { inventory4(); } | |
if (units[currentUnitIndex].inventory.Count == 5) { inventory5(); } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment