//This can return null. public static Tile FindTileNextToTarget(TacticsMovement _origin, TacticsMovement _target) { _origin.GetCurrentTile(); Tile closestTile = null; float maxDistance = Mathf.Infinity; foreach (Neighbour neighbour in _target.currentTile.neighbours) { if (neighbour != null) { foreach (Tile tileCanBeWalkedTo in _origin.selectableTiles) { if (tileCanBeWalkedTo == neighbour.tile) { if (Vector3.Distance(_origin.transform.position, tileCanBeWalkedTo.transform.position) < maxDistance) { maxDistance = Vector3.Distance(_origin.transform.position, tileCanBeWalkedTo.transform.position); closestTile = neighbour.tile; } } } } } return closestTile; }
public static void DeleteUnit(TacticsMovement unit) { turnTeam.Enqueue(unit); list.Remove(unit); units[unit.tag].Remove(unit); Destroy(unit.gameObject); }
public static Tile FindFlankingTile(TacticsMovement origin, List<Tile> tiles, TacticsMovement target) { Tile flankingTile = null; FindAdjacentUnits(target); foreach (TacticsMovement u in target.adjacentUnits) { if (u != origin) { if (u.unitInfo.faction == origin.unitInfo.faction) { u.GetCurrentTile(); Tile allyTile = u.currentTile; Vector3 flankingTileLocation = allyTile.transform.position + ((target.currentTile.transform.position - allyTile.transform.position) * 2); Vector3 overlapBoxSize = new Vector3(.25f, origin.jumpHeight * 4, .25f); Collider[] colliders = Physics.OverlapBox(flankingTileLocation, overlapBoxSize); foreach (Collider collider in colliders) { if (collider.tag == "tile") { flankingTile = collider.gameObject.GetComponent<Tile>(); } } } } } if (tiles.Contains(flankingTile)) return flankingTile; else return null; }
//NPC only AI tool for checking there is an A* path to a target. public static bool PathFound(NPC originUnit, TacticsMovement target) { originUnit.destination = target.gameObject; target.GetCurrentTile(); Tile t = originUnit.FindPath(target.currentTile); originUnit.destination = null; if (t != null) { return true; } else { return false; } }
public virtual void AddTarget(TacticsMovement unit, Tile tileToAttackFrom) { Target target = new Target { unitTargeted = unit }; targets.Add(target); }
public override void AddTarget(TacticsMovement unit, Tile tileToAttackFrom) { Target target = new Target { unitTargeted = unit, tileToAttackFrom = tileToAttackFrom }; targets.Add(target); }
public static Tile FindTileToDodgeTo(TacticsMovement defender, Unit attacker, int direction) { List<Neighbour> viableNeighbours = new List<Neighbour>(); List<Tile> tiles = new List<Tile>(); //if it's a ranged attack, pick squares to the side and add them to the list. if (attacker.mainWeapon.weaponData.rangeType == WeaponData.Range.ranged) { int opposite = GetDirection(direction + 4); for (int count = 0; count < 8; count++) { if (defender.currentTile.neighbours[count] != null) { if (count != direction && count != opposite) { viableNeighbours.Add(defender.currentTile.neighbours[count]); } } } } //if it's melee then dodge away or to the side. else if (attacker.mainWeapon.weaponData.rangeType == WeaponData.Range.melee) { int right = GetDirection(direction - 1); int left = GetDirection(direction + 1); for (int count = 0; count < 8; count++) { if (defender.currentTile.neighbours[count] != null) { if (count != direction && count != right && count != left) { viableNeighbours.Add(defender.currentTile.neighbours[count]); } } } } if (viableNeighbours.Count == 0) return null; //Check squares on the list for all that are unobscured, empty and don't have any height difference. foreach (Neighbour neighbour in viableNeighbours) { if (neighbour.height <= 0 && neighbour.tile.occupant == null && !neighbour.tile.difficultTerrain) { tiles.Add(neighbour.tile); } } if (tiles.Count == 0) return null; int r = UnityEngine.Random.Range(0, tiles.Count); return tiles[r]; }
public static void FollowUnit(TacticsMovement unit) { if (unitCurrentlyFollowed != null) { unit.vcam.transform.position = unitCurrentlyFollowed.transform.position; } //Move the new unit's camera to be top of the subqueue. playerControl = false; unit.vcam.MoveToTopOfPrioritySubqueue(); unitCurrentlyFollowed = unit; }
public static void ResetStatics() { currentUnit = null; enemies.Clear(); queuedActions = 0; sortedUnits.Clear(); unsortedUnits.Clear(); order.Clear(); players.Clear(); initiativeManager = null; OnEncounterStart = null; }
void CheckMouse() { if (Input.GetMouseButtonUp(0)) { if (!EventSystem.current.IsPointerOverGameObject()) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { //Work out if a TacticsMovement has been selected. if (hit.collider.GetComponent <TacticsMovement>() != null) { TacticsMovement UnitClickedOn = hit.collider.GetComponent <TacticsMovement>(); if (canFocusSwitch) { if (RangeFinder.LineOfSight(this, UnitClickedOn) == true) { SetFocus(UnitClickedOn); remainingActions = 0; remainingMove = 0; Initiative.queuedActions++; StartCoroutine(Initiative.CheckForTurnEnd()); } } else if (remainingActions > 0) { foreach (Weapon.Target target in mainWeapon.targets) { if (target.unitTargeted == UnitClickedOn) { Initiative.queuedActions += mainWeapon.weaponData.actionsPerAttack; mainWeapon.StartCoroutine("Attack", target); return; } } } } else if (hit.collider.tag == "Tile Select") { Tile t = hit.collider.transform.parent.GetComponent <Tile>(); if (t.selectable) { Initiative.queuedActions++; MoveToTile(t); return; } } } } } }
static void StartTurn() { currentUnit = order.Peek(); currentUnit.ResetActions(); order.Peek().BeginTurn(); GameObject selector = GameObject.FindGameObjectWithTag("selector"); selector.transform.SetParent(currentUnit.transform, false); actionUIManager.UpdateActions(currentUnit.GetComponent <TacticsMovement>()); CinemachineCamera.FollowUnit(currentUnit.GetComponent <TacticsMovement>()); OnTurnStart(currentUnit); CombatLog.UpdateCombatLog(currentUnit.name + "(" + currentUnit.gameObject.GetInstanceID() + ")" + " starts turn."); }
//Tile Filters public static List<Tile> FindTilesWithLineOfSight(TacticsMovement origin, List<Tile> tiles, TacticsMovement target) { float offset = 0.5f + origin.halfHeight; List<Tile> filteredTiles = new List<Tile>(); foreach (Tile t in tiles) { Vector3 POV = t.transform.position + new Vector3(0, offset); if (Physics.Raycast(POV, (target.gameObject.transform.position + new Vector3(0, target.GetComponent<TacticsMovement>().halfHeight) - POV), out RaycastHit hit)) { if (hit.collider.GetComponent<TacticsMovement>() == target) { filteredTiles.Add(t); } } } return filteredTiles; }
public static void EndTurn() { TacticsMovement unit = turnTeam.Dequeue(); unit.EndTurnUnit(); if (turnTeam.Count > 0) { StartTurn(); } else { string team = turnKey.Dequeue(); turnKey.Enqueue(team); InitTeamTurnQueue(); } }
public static IEnumerator EndTurn(bool delay = false) { CombatLog.UpdateCombatLog(currentUnit.name + "(" + currentUnit.gameObject.GetInstanceID() + ")" + " ends turn. \r\n"); currentUnit = null; TacticsMovement unit = order.Dequeue(); unit.EndTurn(); if (delay == true) { yield return(new WaitForSeconds(1f)); } order.Enqueue(unit); StartTurn(); yield break; }
public static void FindAdjacentUnits(TacticsMovement unit) { unit.adjacentUnits.Clear(); foreach (Neighbour n in unit.currentTile.neighbours) { if (n != null) { if (n.tile != null) { if (n.tile.occupant != null) { unit.adjacentUnits.Add(n.tile.occupant); } } } } }
public static Tile FindTileFurthestFromOpponents(TacticsMovement origin, List<Tile> tiles) { Tile furthest = null; float highestRunValue = 0f; foreach (Tile t in tiles) { float runValue = 0f; foreach (Unit opponent in Initiative.players) { runValue += Vector3.Distance(opponent.transform.position, t.transform.position); } if (runValue > highestRunValue) { furthest = t; highestRunValue = runValue; } } return furthest; }
public static void AddUnit(TacticsMovement unit) { if (!units.ContainsKey(unit.tag)) { list = new List <TacticsMovement>(); units[unit.tag] = list; if (!turnKey.Contains(unit.tag)) { turnKey.Enqueue(unit.tag); } } else { list = units[unit.tag]; } list.Add(unit); }
public static List<Tile> FindTilesNotNextToEnemy(TacticsMovement origin, List<Tile> tiles, Factions opposingFaction) { List<Tile> filteredTiles = new List<Tile>(); List<Unit> opponents = new List<Unit>(); switch (opposingFaction) { case Factions.players: opponents = Initiative.players; break; case Factions.enemies: opponents = Initiative.enemies; break; default: break; } foreach (Tile t in tiles) { bool found = false; foreach (Unit opponent in opponents) { TacticsMovement opponentTactics = opponent.GetComponent<TacticsMovement>(); //The next line shouldn't be needed as tiles should be allocated when a unit moves into them. opponentTactics.GetCurrentTile(); //opponentTactics.currentTile.FindNeighbours(opponentTactics.jumpHeight, null); opponentTactics.currentTile.CheckNeighbours(opponentTactics.jumpHeight, null); foreach (Tile orthagonalTile in opponentTactics.currentTile.adjacencyList) { if (t == orthagonalTile) found = true; } foreach (Tile diagonalTile in opponentTactics.currentTile.diagonalAdjacencyList) { if (t == diagonalTile) found = true; } } if (!found) filteredTiles.Add(t); } return filteredTiles; }
public static void DamageRoll(TacticsMovement attacker, Unit defender, Result attackResult) { damage += attacker.unitInfo.currentDamage; resiliance += defender.unitInfo.currentToughness; if (!armourPierce) { resiliance += defender.unitInfo.currentArmour; } //Blocking if (defenceType == DefenceType.BLOCK) { blockDice = -1; defender.gameObject.GetComponent <UnitPopUpManager>().AddPopUpInfo("blocked"); } if (defenceType == DefenceType.SHIELD) { blockDice = -2; defender.gameObject.GetComponent <UnitPopUpManager>().AddPopUpInfo("shielded"); } AbilityCheck.CheckAbility(damage, resiliance, blockDice); int result = AbilityCheck.baseResult; //assumes all are 'fated' for now. if (result < -9) { defender.gameObject.GetComponent <UnitPopUpManager>().AddPopUpInfo("shrugged"); return; } else if (result < 1) { OnGraze(attacker, defender); //Alert all that someone is grazed. defender.UpdateBreath(grazeDamage); struckAnimation = StruckAnimation.GRAZE; } else { OnWound(attacker, defender); //Alert all that someone is wounded. if (result > 9) { wounds = 3; } else if (result > 4) { wounds = 2; } else { wounds = 1; } defender.UpdateWounds(wounds, woundValueAdjustment); struckAnimation = StruckAnimation.WOUND; } //Resolve all post-damage criticals. foreach (Critical c in CriticalManager.criticalChain) { if (c.AfterDamage() == true) { c.CriticalEffect(); } } switch (struckAnimation) { case StruckAnimation.SHIELD: defender.unitAnim.SetTrigger("shield"); break; case StruckAnimation.BLOCK: defender.unitAnim.SetTrigger("block"); break; case StruckAnimation.GRAZE: defender.unitAnim.SetTrigger("graze"); break; case StruckAnimation.WOUND: defender.unitAnim.SetTrigger("wound"); break; default: break; } if (defender.focus != attacker) { defender.SetFocus(attacker); } }
public static void Display(TacticsMovement unit) { display = true; targetUnit = unit; }
public static void AddUnit(TacticsMovement unit) { unsortedUnits.Add(unit); }
public override void DoTask(NPC unit, Unit targetUnit = null, Tile targetTile = null) { //Check to see if the target has been removed. If so, end turn. if (target == null && attacked == true) { flagEndofTurn = true; return; } //if a flank is available, move to it. if (!inFlankingPosition && !firstMoveDone) { unit.FindSelectableTiles(); Tile flankingTile = RangeFinder.FindFlankingTile(unit, unit.selectableTiles, target.GetComponent <TacticsMovement>()); if (flankingTile != null && unit.remainingMove > 0) { inFlankingPosition = true; Initiative.queuedActions++; CombatLog.UpdateCombatLog(unit.name + " moves to flank."); unit.MoveToTile(flankingTile); firstMoveDone = true; return; } } //Move as close as possible if main action is available and you're not next to the target. RangeFinder.FindAdjacentUnits(unit); if (!unit.adjacentUnits.Contains(target) && !firstMoveDone) { if (unit.remainingActions > 0 && unit.remainingMove > 0) { unit.destination = target.gameObject; CombatLog.UpdateCombatLog(unit.name + " A* toward opposing faction."); firstMoveDone = true; return; } } //Attack if in the right position if (unit.remainingActions > 0) { RangeFinder.FindAdjacentUnits(unit); if (unit.adjacentUnits.Contains(target)) { foreach (Weapon.Target t in unit.mainWeapon.targets) { if (t.unitTargeted == target) { Initiative.queuedActions += 1; unit.mainWeapon.StartCoroutine("Attack", t); CombatLog.UpdateCombatLog(unit.name + " attacks " + target.name); attacked = true; return; } } } } //Move away if you have move left if (unit.remainingMove >= 1) { unit.FindSelectableTiles(); //A Hack to solve the bug 'characters teleport rather than move, and can share spaces'. This isn't working. TacticsMovement targetT = target.GetComponent <TacticsMovement>(); targetT.GetCurrentTile(); if (unit.selectableTiles.Contains(targetT.currentTile)) { unit.selectableTiles.Remove(targetT.currentTile); } List <Tile> preferedTiles = RangeFinder.FindTilesNotNextToEnemy(unit, unit.selectableTiles, Factions.players); if (preferedTiles.Count > 0) { Initiative.queuedActions++; CombatLog.UpdateCombatLog(unit.name + " moves away."); unit.MoveToTile(preferedTiles[Random.Range(0, preferedTiles.Count)]); flagEndofTurn = true; return; } } //Defend if you've not reached the target if (unit.remainingActions > 0) { CombatLog.UpdateCombatLog(unit.name + " defends."); unit.defend.ExecuteAction(ActionCost.main); return; } flagEndofTurn = true; }
// Start is called before the first frame update void Start() { unit = gameObject.transform.parent.GetComponent <TacticsMovement>(); gameObject.transform.parent = null; }
public void UpdateActions(TacticsMovement unit) { Clear(); //set all the info out for the selected unit currentUnit = unit; unitName.text = unit.unitInfo.unitName; weaponImage.sprite = unit.unitInfo.mainWeaponData.SetImage(); firstBreathSlider.maxValue = unit.unitInfo.firstBreath; firstBreathSlider.value = unit.unitInfo.currentBreath - unit.unitInfo.flaggingBreath; flaggingBreathSlider.maxValue = unit.unitInfo.flaggingBreath; flaggingBreathSlider.value = unit.unitInfo.currentBreath; TacticsMovement unitTactics = unit.GetComponent <TacticsMovement>(); foreach (Effect effect in unit.effects) { AddEffectIcon(effect, statusEffects.transform); } if (unitTactics.remainingMove >= unit.unitInfo.currentMove) { moveAvailable = true; } else { moveAvailable = false; } if (unitTactics.remainingActions >= 1) { mainAvailable = true; } else { mainAvailable = false; } if (moveAvailable) { moveActionButton.SetActive(true); } else { moveActionButton.SetActive(false); } if (mainAvailable) { mainActionButton.SetActive(true); } else { mainActionButton.SetActive(false); } focusBeingSelected = false; if (!currentUnit.focusSwitched) { focusSwitch.gameObject.SetActive(true); focusActiveIndicator.SetActive(false); } else { focusSwitch.gameObject.SetActive(false); } if (unit != null && unit.unitInfo.faction == Factions.players) { endTurn.gameObject.SetActive(true); if (unit.remainingMove > 0 || unit.remainingActions > 0) { focusButton.gameObject.SetActive(true); defenceToggle.gameObject.SetActive(true); DefenceTypeSet(true); //Ensure conditions for actions are met. foreach (Action a in unit.actions) { if (a.CheckAvailable()) { if (moveAvailable) { if (a.actionCost == ActionCost.move) { moveActions.Add(a); } } if (mainAvailable) { if (a.actionCost == ActionCost.main || a.actionCost == ActionCost.move) { mainActions.Add(a); } } } } for (int count = 0; count < moveActions.Count; count++) { AddActionButton(moveActions, count, customMoveActions, ActionCost.move); } for (int count = 0; count < mainActions.Count; count++) { AddActionButton(mainActions, count, customMainActions, ActionCost.main); } } //else Clear(); } else { //This is for NPC actions. Clear(); defenceToggle.gameObject.SetActive(false); return; } }