public override IEnumerator Execute() { map.FindSelectableTiles(currUnit.currentTile, currUnit.stats[StatString.MOVEMENT_RANGE].Value); yield return(new WaitForSecondsRealtime(0.75f)); List <Tile> targets = turnScheduler.players.ConvertAll(x => x.currentTile); Tile targetTile = AStarSearch.GeneratePathToNearestTarget(map, currUnit.currentTile, targets, false, true); Unit targetPlayer = turnScheduler.players.Find(x => x.currentTile == targetTile); // check if target tile is selectable, and also go as far from movement range as possible int distanceFromTarget = 0, attackRange = (int)currUnit.stats[StatString.ATTACK_RANGE].Value; while ((!targetTile.selectable || distanceFromTarget < attackRange) && targetTile != currUnit.currentTile) { distanceFromTarget++; targetTile = targetTile.parent; } // A star movement towards the target currUnit.GetPathToTile(targetTile); yield return(new WaitUntil(() => currUnit.CurrState == UnitState.IDLING)); // check if there are players in range if (map.PlayerTargetInAttackRange(currUnit.currentTile, currUnit.stats[StatString.ATTACK_RANGE].Value, targetPlayer)) { currUnit.attackingTargetUnit = targetPlayer; turnScheduler.SetState(new EnemyAttack(turnScheduler)); } else { turnScheduler.SetState(new EnemyEndTurn(turnScheduler)); } }
public override IEnumerator Execute() { map.FindSelectableTiles(currUnit.currentTile, currUnit.stats[StatString.MOVEMENT_RANGE].Value); yield return(new WaitForSecondsRealtime(0.25f)); List <Tile> targets = turnScheduler.players.ConvertAll(x => x.currentTile); Tile targetTile = AStarSearch.GeneratePathToNearestTarget(map, currUnit.currentTile, targets, false, true); Unit targetPlayer = turnScheduler.players.Find(x => x.currentTile == targetTile); // check if target tile is selectable, and also go as far from movement range as possible int cautiousRange = 2; while (!targetTile.selectable || targetTile.distance > cautiousRange) { targetTile = targetTile.parent; } // A star movement towards the target, 70% of the time, 10% of time will choose a random target and go int chance = new Random().Next(1, 100); if (chance <= 70) { currUnit.GetPathToTile(targetTile); } else if (chance >= 90) { List <Tile> closeTiles = map.GetSelectableTiles().ToList().FindAll(tile => tile.distance <= 2); targetTile = closeTiles[new Random().Next(0, closeTiles.Count - 1)]; currUnit.GetPathToTile(targetTile); } yield return(new WaitUntil(() => currUnit.CurrState == UnitState.IDLING)); turnScheduler.SetState(new EnemyEndTurn(turnScheduler)); }
// decide order of movement // decide who is in recovery mode // decide who is going to heal those in recovery mode public LinkedList <Unit> StartTurn(List <PlayerUnit> players, List <EnemyUnit> enemies, Map map, LinkedList <Unit> currTeamQueue) { UpdateGameState(players, enemies, map); List <EnemyUnit> unitsInRecoveryMode = new List <EnemyUnit>(); // Assign recovery mode foreach (EnemyUnit enemyUnit in enemies) { if (enemyUnit.IsRecoveryMode() && enemyUnit.selfHealingAbilities.Count == 0) { unitsInRecoveryMode.Add(enemyUnit); } } Queue <EnemyUnit> unassignedMedics = new Queue <EnemyUnit>(medics); List <EnemyUnit> remainingHurtUnits = new List <EnemyUnit>(unitsInRecoveryMode); medics.ForEach(unit => unit.ResetMedicStatus()); // Assign targets to medics = will keep running as long as there are there are both unassignedHurtUnits and unassignedMedics while (unitsInRecoveryMode.Count > 0 && unassignedMedics.Count > 0) { EnemyUnit currMedic = unassignedMedics.Dequeue(); bool foundTarget = false; List <EnemyUnit> remainingHurtUnitsToSearch = new List <EnemyUnit>(unitsInRecoveryMode); while (!foundTarget && remainingHurtUnitsToSearch.Count > 0) { // Find closest target Tile targetTile = AStarSearch.GeneratePathToNearestTarget(map, currMedic.currentTile, remainingHurtUnitsToSearch.ConvertAll(input => input.currentTile), false, true); EnemyUnit medicTarget = unitsInRecoveryMode.Find(unit => unit.currentTile == targetTile); // if already assigned to another medic, compare relative distance if (!remainingHurtUnits.Contains(medicTarget)) { EnemyUnit oldMedic = medics.Find(unit => unit.medicTarget == medicTarget); if (targetTile.distance < oldMedic.distanceToMedicTarget) { currMedic.medicTarget = medicTarget; currMedic.distanceToMedicTarget = targetTile.distance; oldMedic.ResetMedicStatus(); unassignedMedics.Enqueue(oldMedic); foundTarget = true; } else { remainingHurtUnitsToSearch.Remove(medicTarget); } } // new target, has not been assigned a medic else { currMedic.medicTarget = medicTarget; currMedic.distanceToMedicTarget = targetTile.distance; foundTarget = true; remainingHurtUnits.Remove(medicTarget); } } } LinkedList <Unit> updatedCurrTeamQueue = new LinkedList <Unit>(currTeamQueue); // Reorder the queue: hurt people first, then medics foreach (Unit hurtUnit in unitsInRecoveryMode.FindAll(unit => !remainingHurtUnits.Contains(unit))) { updatedCurrTeamQueue.Remove(hurtUnit); updatedCurrTeamQueue.AddFirst(hurtUnit); } return(updatedCurrTeamQueue); }