diff --git a/Assets/Scripts/Model/Actions/ActionsList/BoostAction.cs b/Assets/Scripts/Model/Actions/ActionsList/BoostAction.cs index 586d278c7c..c47bccaaa0 100644 --- a/Assets/Scripts/Model/Actions/ActionsList/BoostAction.cs +++ b/Assets/Scripts/Model/Actions/ActionsList/BoostAction.cs @@ -1,13 +1,22 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; +using Actions; +using ActionsList; +using AI; using BoardTools; -using GameModes; -using System.Linq; using Editions; +using GameModes; using Obstacles; -using ActionsList; -using Actions; +using Players; +using Ship; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + + + + + + namespace ActionsList { @@ -44,6 +53,19 @@ public override void RevertActionOnFail(bool hasSecondChance = false) { Phases.GoBack(); } + + public override int GetActionPriority() + { + int result = 0; + + // Check to see if we are before the maneuver phase or not. + bool isBeforeManeuverPhase = !Selection.ActiveShip.AiPlans.shipHasManeuvered; + // Until I get Advanced Sensors fixed... + isBeforeManeuverPhase = false; + result = AI.Aggressor.NavigationSubSystem.TryActionPossibilities(this, isBeforeManeuverPhase); + + return result; + } } public class BoostMove @@ -130,8 +152,23 @@ public void StartBoostPlanning() AvailableBoostMoves = TheShip.GetAvailableBoostTemplates(); InitializeRendering(); - - AskSelectTemplate(); + if (TheShip.Owner.PlayerType == PlayerType.Ai) + { + // We have AI here. Do AI things. + AiSinglePlan aiBoostAction = TheShip.AiPlans.GetPlanByActionName("Boost"); + if (aiBoostAction != null) + { + SelectTemplateByName(aiBoostAction.actionName, aiBoostAction.isRedAction); + + // Now that we're done with the plan, remove it. + TheShip.AiPlans.RemovePlan(aiBoostAction); + } + } + else + { + // We have a player here. Ask them about their boost. + AskSelectTemplate(); + } } private void AskSelectTemplate() @@ -188,6 +225,25 @@ private void SelectTemplate(BoostMove move) DecisionSubPhase.ConfirmDecision(); } + private void SelectTemplateByName(string actionName, bool isRed) + { + if (isRed && !HostAction.IsRed) + { + HostAction.Color = ActionColor.Red; + TheShip.OnActionIsPerformed += ResetActionColor; + } + + SelectedBoostHelper = actionName; + if (TheShip.Owner.PlayerType == PlayerType.Ai) + { + SelectTemplateDecisionIsTaken(); + } + else + { + DecisionSubPhase.ConfirmDecision(); + } + } + private void ResetActionColor(GenericAction action) { action.HostShip.OnActionIsPerformed -= ResetActionColor; @@ -316,7 +372,24 @@ private void GetResults(System.Action canBoostCallback = null) } else { - GameMode.CurrentGameMode.CancelBoost(boostProblems); + if (TheShip.Owner.PlayerType == PlayerType.Ai) + { + // Skip the failed boost action. + GameMode.CurrentGameMode.FinishBoost(); + string tempName = Phases.CurrentSubPhase.Name; + Phases.CurrentSubPhase = Phases.CurrentSubPhase.PreviousSubPhase; + tempName = Phases.CurrentSubPhase.Name; + + UpdateHelpInfo(); + + + + CallBack(); + } + else + { + GameMode.CurrentGameMode.CancelBoost(boostProblems); + } } } @@ -433,6 +506,7 @@ private void FinishBoostAnimation() { Phases.CurrentSubPhase = Phases.CurrentSubPhase.PreviousSubPhase; Phases.CurrentSubPhase = Phases.CurrentSubPhase.PreviousSubPhase; + UpdateHelpInfo(); CallBack(); @@ -449,5 +523,6 @@ public override bool AnotherShipCanBeSelected(Ship.GenericShip anotherShip, int bool result = false; return result; } + } } diff --git a/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationResult.cs b/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationResult.cs index 858013e382..063e98c0de 100644 --- a/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationResult.cs +++ b/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationResult.cs @@ -12,6 +12,7 @@ public class NavigationResult public bool isLandedOnObstacle; public int enemiesInShotRange; + public int enemiesTargetingThisShip; public int obstaclesHit; public int minesHit; @@ -42,7 +43,10 @@ public void CalculatePriority() if (isOffTheBoardNextTurn) Priority -= 20000; + // Base our priority off of how many enemies can shoot us versus how many we can shoot. Priority += enemiesInShotRange * 1000; + // Allow up to two enemies targeting us to equal one enemy in our attack range. + // Priority -= enemiesTargetingThisShip * 500; Priority -= obstaclesHit * 2000; Priority -= minesHit * 2000; diff --git a/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationSubSystem.cs b/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationSubSystem.cs index e7ae58bb8f..5c092eaccf 100644 --- a/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationSubSystem.cs +++ b/Assets/Scripts/Model/Ai/Aggressor/NavigationSubSystem/NavigationSubSystem.cs @@ -1,4 +1,5 @@ -using System; +using ActionsList; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -248,14 +249,25 @@ private static IEnumerator ProcessMovementPredicition() //In arc - improve int enemiesInShotRange = 0; + int enemiesThatCanShootUs = 0; float minDistanceToNearestEnemyInShotRange = 0; + ShotInfo enemyCanShootThisShip = null; foreach (GenericShip enemyShip in CurrentShip.Owner.EnemyShips.Values) { + // See if we can shoot this enemy. ShotInfo shotInfo = new ShotInfo(CurrentShip, enemyShip, CurrentShip.PrimaryWeapons.First()); if (shotInfo.IsShotAvailable) { enemiesInShotRange++; if (minDistanceToNearestEnemyInShotRange < shotInfo.DistanceReal) minDistanceToNearestEnemyInShotRange = shotInfo.DistanceReal; + + + } + // See if this enemy can shoot us. + enemyCanShootThisShip = new ShotInfo(enemyShip, CurrentShip, enemyShip.PrimaryWeapons.First()); + if (enemyCanShootThisShip.IsShotAvailable == true) + { + enemiesThatCanShootUs++; } } @@ -265,6 +277,7 @@ private static IEnumerator ProcessMovementPredicition() distanceToNearestEnemy = minDistanceToEnenmyShip, distanceToNearestEnemyInShotRange = minDistanceToNearestEnemyInShotRange, enemiesInShotRange = enemiesInShotRange, + enemiesTargetingThisShip = enemiesThatCanShootUs, isBumped = CurrentMovementPrediction.IsBumped, isLandedOnObstacle = CurrentMovementPrediction.IsLandedOnAsteroid, obstaclesHit = CurrentMovementPrediction.AsteroidsHit.Count, @@ -326,5 +339,338 @@ private static bool IsActivationBeforeCurrentShip(GenericShip ship) || (ship.State.Initiative == CurrentShip.State.Initiative && ship.Owner.PlayerNo == Phases.PlayerWithInitiative && ship.Owner.PlayerNo != CurrentShip.Owner.PlayerNo) || (ship.State.Initiative == CurrentShip.State.Initiative && ship.ShipId < CurrentShip.ShipId && ship.Owner.PlayerNo == CurrentShip.Owner.PlayerNo); } + + // This function will try all moves related to a boost, barrelroll, decloak, SLAM, or tractor. If the action is from Supernatural Reflexes or Advanced Sensors, + // it will also test the maneuver that follows it to see if that is better or worse than without taking the action before it. + public static int TryActionPossibilities(GenericAction actionToTry, bool isBeforeManeuverPhase = false) + { + VirtualBoard myBoard = new VirtualBoard(); + int result = 0; + GenericShip thisShip = Selection.ActiveShip; + GenericMovement savedMovement = thisShip.AssignedManeuver; + int shieldHullTotal = thisShip.State.ShieldsCurrent + thisShip.State.HullCurrent; + int startingResult = 0; + + NavigationResult StartingPosition = null; + ShipPositionInfo shipOriginalPosition = thisShip.GetPositionInfo(); + + // Prepare our virtual board maneuver tests. + myBoard.UpdatePositionInfo(thisShip); + + // Record our current position for comparison. + if (isBeforeManeuverPhase == true) + { + // Our action is before a maneuver. Find out the results for our maneuver if we don't boost/barrel-roll/decloak before it. + MovementPrediction maneuverWithoutActionFirst = new MovementPrediction(thisShip.AssignedManeuver); + myBoard.SetVirtualPositionInfo(thisShip, maneuverWithoutActionFirst.FinalPositionInfo); + myBoard.SwitchToVirtualPosition(thisShip); + StartingPosition = GetCurrentPositionNavigationInfo(thisShip, maneuverWithoutActionFirst); + myBoard.SwitchToRealPosition(thisShip); + + // Move us back to before the maneuver. + myBoard.SetVirtualPositionInfo(thisShip, shipOriginalPosition); + } + else + { + // Just record our current position. + myBoard.SwitchToVirtualPosition(thisShip); + StartingPosition = GetCurrentPositionNavigationInfo(thisShip); + myBoard.SwitchToRealPosition(thisShip); + } + + // Test for a boost action. + if (actionToTry is BoostAction) + { + // Determine how good our starting position is. + startingResult = CalculateBoostPositionPriority(StartingPosition); + result = TryBoostAction(myBoard, thisShip, shipOriginalPosition, StartingPosition, startingResult, isBeforeManeuverPhase); + } + + // Restore our original move. + if (savedMovement != null) + { + thisShip.SetAssignedManeuver(savedMovement, isSilent: true); + } + else + { + thisShip.ClearAssignedManeuver(); + } + + return result; + } + + // Set navigation information for the current ship's position. + private static NavigationResult GetCurrentPositionNavigationInfo(GenericShip thisShip, MovementPrediction firstMovement = null, MovementPrediction secondMovement = null) + { + NavigationResult currentNavigationResult = new NavigationResult() + { + movement = thisShip.AssignedManeuver, + distanceToNearestEnemy = 0, + distanceToNearestEnemyInShotRange = 0, + enemiesInShotRange = 0, + enemiesTargetingThisShip = 0, + isBumped = thisShip.IsBumped, + isLandedOnObstacle = thisShip.IsLandedOnObstacle, + obstaclesHit = 0, + isOffTheBoard = false, + minesHit = 0, + isOffTheBoardNextTurn = false, + isHitAsteroidNextTurn = false, + FinalPositionInfo = thisShip.GetPositionInfo() + }; + + // Duplicate all information we can from our movement prediction(s). + if(firstMovement != null) + { + if(secondMovement != null) + { + currentNavigationResult.movement = secondMovement.CurrentMovement; + currentNavigationResult.isBumped = (secondMovement.IsBumped || firstMovement.IsBumped); + currentNavigationResult.isLandedOnObstacle = (secondMovement.IsLandedOnAsteroid || firstMovement.IsLandedOnAsteroid); + currentNavigationResult.obstaclesHit = (secondMovement.AsteroidsHit.Count + firstMovement.AsteroidsHit.Count); + currentNavigationResult.isOffTheBoard = (secondMovement.IsOffTheBoard || firstMovement.IsOffTheBoard); + currentNavigationResult.minesHit = (secondMovement.MinesHit.Count + firstMovement.MinesHit.Count); + } + else + { + currentNavigationResult.movement = firstMovement.CurrentMovement; + currentNavigationResult.isBumped = firstMovement.IsBumped; + currentNavigationResult.isLandedOnObstacle = firstMovement.IsLandedOnAsteroid; + currentNavigationResult.obstaclesHit = firstMovement.AsteroidsHit.Count; + currentNavigationResult.isOffTheBoard = firstMovement.IsOffTheBoard; + currentNavigationResult.minesHit = firstMovement.MinesHit.Count; + } + } + + int enemiesInShotRange = 0; + + float minDistanceToNearestEnemyInShotRange = float.MaxValue; + CurrentShip = thisShip; + foreach (GenericShip enemyShip in thisShip.Owner.EnemyShips.Values) + { + if (IsActivationBeforeCurrentShip(enemyShip)) + { + // This enemy acts before us. They won't be able to leave our targeting arc. + // Get our weapon shot info for each arc that has a weapon pointing in it. + foreach (IShipWeapon currentWeapon in thisShip.GetAllWeapons()) + { + ShotInfo shotInfo = new ShotInfo(thisShip, enemyShip, currentWeapon); + if (shotInfo.IsShotAvailable) + { + // We are looking for our closest enemy target. + enemiesInShotRange++; + if (minDistanceToNearestEnemyInShotRange > shotInfo.DistanceReal) minDistanceToNearestEnemyInShotRange = shotInfo.DistanceReal; + } + } + } + } + + currentNavigationResult.enemiesInShotRange = enemiesInShotRange; + currentNavigationResult.distanceToNearestEnemyInShotRange = minDistanceToNearestEnemyInShotRange; + + // Find the nearest distance to an enemy ship. + float minDistanceToEnemyShip = float.MaxValue; + ShotInfo enemyCanShootThisShip = null; + foreach (GenericShip enemyShip in thisShip.Owner.EnemyShips.Values) + { + DistanceInfo distInfo = new DistanceInfo(CurrentShip, enemyShip); + if (distInfo.MinDistance.DistanceReal < minDistanceToEnemyShip) + { + if(distInfo.MinDistance.DistanceReal != 0 || thisShip.IsBumped == true) + { + // A value of 0 is false unless we've bumped. + minDistanceToEnemyShip = distInfo.MinDistance.DistanceReal; + } + + } + + // See if this enemy can shoot us with any of its weapons. + foreach (IShipWeapon currentWeapon in thisShip.GetAllWeapons()) + { + enemyCanShootThisShip = new ShotInfo(enemyShip, thisShip, currentWeapon); + if (enemyCanShootThisShip.IsShotAvailable == true) + { + currentNavigationResult.enemiesTargetingThisShip++; + break; + } + } + } + + currentNavigationResult.distanceToNearestEnemy = minDistanceToEnemyShip; + + return currentNavigationResult; + } + + // Determine how good the position we have been passed is. + private static int CalculateBoostPositionPriority(NavigationResult CurrentPosition) + { + int Priority = 0; + if (CurrentPosition.isOffTheBoard) + { + return 0; + } + if (CurrentPosition.isLandedOnObstacle) Priority -= 20000; + + if (CurrentPosition.isOffTheBoardNextTurn) Priority -= 20000; + + // Base our priority off of how many enemies can shoot us versus how many we can shoot. + if (CurrentPosition.enemiesInShotRange > 0) + { + // We have at least one enemy in shot range. We don't need to maximize our targets. + Priority += 20; + if(CurrentPosition.distanceToNearestEnemyInShotRange < 1) + { + // We are at range 1 of a target? + Priority += 10; + } + } + // Reduce our priority by the number of enemies that can still target us after the action. + Priority -= CurrentPosition.enemiesTargetingThisShip * 40; + if(CurrentPosition.enemiesTargetingThisShip == 0) + { + // Any position that leads to no-one attacking us is a pretty good position. + Priority += 10; + if(CurrentPosition.enemiesInShotRange > 0) + { + // We have no-one targeting us and at least one target in range. A really good action! + Priority += 30; + } + } + + if (CurrentPosition.obstaclesHit > 0) + { + Priority -= CurrentPosition.obstaclesHit * 2000; + } + Priority -= CurrentPosition.minesHit * 2000; + + if (CurrentPosition.isBumped) + { + // Leave space for testing Arvyl and Zeb. Otherwise, we want to avoid this. + Priority -= 1000; + } + + // Set our priority between 0 and 90. + if(Priority < 0) + { + Priority = 0; + } + + return Priority; + } + + // Given a ship, their starting position, their current navigation results and its priority, determine which, if any, boost action is best for us. If this action + // takes place before the maneuver phase, calculate our results based on our chosen maneuver. + private static int TryBoostAction(VirtualBoard myBoard, GenericShip thisShip, ShipPositionInfo shipOriginalPosition, NavigationResult StartingPosition, int startingResult, bool isBeforeManeuverPhase = false) + { + int result = 0; + int bestBoostResult = 0; + string bestBoostName = "1.S"; + GenericMovement bestBoostMove = null; + NavigationResult bestBoostNavigation = null; + AiSinglePlan bestPlan = new AiSinglePlan(); + + NavigationResult currentBoostNavigation = null; + int currentBoostResult = 0; + bool bestMoveStresses = false; + + // We're performing a boost action. Check all boost action possibilities. + List AvailableBoostMoves = new List(); + AvailableBoostMoves = thisShip.GetAvailableBoostTemplates(); + int numBoostMoves = AvailableBoostMoves.Count(); + + foreach (BoostMove move in AvailableBoostMoves) + { + string selectedBoostHelper = move.Name; + + MovementPrediction boostPrediction = null; + GenericMovement boostMovement; + // Use the name of our boost action to generate a GenericMovement of the matching type. + switch (selectedBoostHelper) + { + case "Straight 1": + boostMovement = new StraightBoost(1, ManeuverDirection.Forward, ManeuverBearing.Straight, MovementComplexity.None); + break; + case "Bank 1 Left": + boostMovement = new BankBoost(1, ManeuverDirection.Left, ManeuverBearing.Bank, MovementComplexity.None); + break; + case "Bank 1 Right": + boostMovement = new BankBoost(1, ManeuverDirection.Right, ManeuverBearing.Bank, MovementComplexity.None); ; + break; + case "Turn 1 Right": + boostMovement = new TurnBoost(1, ManeuverDirection.Right, ManeuverBearing.Turn, MovementComplexity.None); + break; + case "Turn 1 Left": + boostMovement = new TurnBoost(1, ManeuverDirection.Left, ManeuverBearing.Turn, MovementComplexity.None); + break; + default: + boostMovement = new StraightBoost(1, ManeuverDirection.Forward, ManeuverBearing.Straight, MovementComplexity.None); + break; + } + + // Predict our collisions and future position. + boostMovement.Initialize(); + boostPrediction = new MovementPrediction(boostMovement); + boostPrediction.CalculateMovePredictionFast(); + + myBoard.SetVirtualPositionInfo(thisShip, boostPrediction.FinalPositionInfo); + MovementPrediction maneuverAfterAction = null; + if (isBeforeManeuverPhase == true) + { + // We need to now perform our maneuver from this new position. + maneuverAfterAction = new MovementPrediction(thisShip.AssignedManeuver); + maneuverAfterAction.CalculateMovePredictionFast(); + myBoard.SetVirtualPositionInfo(thisShip, maneuverAfterAction.FinalPositionInfo); + } + + // Find out how good this move is. + myBoard.SwitchToVirtualPosition(thisShip); + + currentBoostNavigation = GetCurrentPositionNavigationInfo(thisShip, boostPrediction, maneuverAfterAction); + myBoard.SwitchToRealPosition(thisShip); + + if (currentBoostNavigation == null) + { + currentBoostResult = -20000; + } + currentBoostResult = CalculateBoostPositionPriority(currentBoostNavigation); + + if (move.IsRed == true) + { + // Make red maneuvers a little less optimal. + currentBoostResult -= 10; + } + + if (currentBoostResult > bestBoostResult) + { + // We have a new best boost result. + bestBoostResult = currentBoostResult; + bestBoostNavigation = currentBoostNavigation; + bestBoostMove = boostMovement; + bestMoveStresses = move.IsRed; + bestBoostName = selectedBoostHelper; + } + + + // Reset our ship position for the next boost test. + myBoard.SetVirtualPositionInfo(thisShip, shipOriginalPosition); + } + if (bestBoostResult > startingResult) + { + // Boosting is better than staying here! + // Since the navigation results can reach a maximum of 8,000 (8 enemies in range, none targeting us), we need the range to be up to 100 to match other priorities. + + result = bestBoostResult; + bestPlan.Priority = bestBoostResult; + bestPlan.currentAction = new BoostAction(); + bestPlan.currentActionMove = bestBoostMove; + bestPlan.actionName = bestBoostName; + bestPlan.isRedAction = bestMoveStresses; + + // Give our ship our new plan. + thisShip.AiPlans.AddPlan(bestPlan); + } + + return result; + } } } diff --git a/Assets/Scripts/Model/Content/Core/Ship/GenericShipMovement.cs b/Assets/Scripts/Model/Content/Core/Ship/GenericShipMovement.cs index 7fbb0b6f4d..fb75afb1cc 100644 --- a/Assets/Scripts/Model/Content/Core/Ship/GenericShipMovement.cs +++ b/Assets/Scripts/Model/Content/Core/Ship/GenericShipMovement.cs @@ -117,7 +117,10 @@ public void CallManeuverIsRevealed(System.Action callBack) { if (OnManeuverIsRevealed != null) OnManeuverIsRevealed(this); if (OnManeuverIsRevealedGlobal != null) OnManeuverIsRevealedGlobal(this); - + if (Selection.ThisShip.AiPlans != null) + { + Selection.ThisShip.AiPlans.shipHasManeuvered = false; + } Triggers.ResolveTriggers(TriggerTypes.OnManeuverIsRevealed, callBack); } else // For ionized ships @@ -131,7 +134,10 @@ public void CallManeuverIsRevealed(System.Action callBack) public void StartMoving(System.Action callback) { if (OnMovementStart != null) OnMovementStart(this); - + if (Selection.ThisShip.AiPlans != null) + { + Selection.ThisShip.AiPlans.shipHasManeuvered = true; + } Triggers.ResolveTriggers(TriggerTypes.OnMovementStart, callback); } diff --git a/Assets/Scripts/Model/Movement/MovementPrediction/MovementPrediction.cs b/Assets/Scripts/Model/Movement/MovementPrediction/MovementPrediction.cs index 18604d7a59..af0eaf3df3 100644 --- a/Assets/Scripts/Model/Movement/MovementPrediction/MovementPrediction.cs +++ b/Assets/Scripts/Model/Movement/MovementPrediction/MovementPrediction.cs @@ -41,6 +41,12 @@ public MovementPrediction(GenericMovement movement) GenerateShipStands(); } + public void CalculateMovePredictionFast() + { + WaitForFrames(4); + GetResults(); + } + public IEnumerator CalculateMovementPredicition() { yield return UpdateColisionDetectionAlt(); diff --git a/Assets/Scripts/View/Ship/GenericShip.cs b/Assets/Scripts/View/Ship/GenericShip.cs index 088dcfd015..4b26ddbdeb 100644 --- a/Assets/Scripts/View/Ship/GenericShip.cs +++ b/Assets/Scripts/View/Ship/GenericShip.cs @@ -1,6 +1,8 @@ -using Arcs; +using ActionsList; +using Arcs; using BoardTools; using Editions; +using Movement; using System.Collections; using System.Collections.Generic; using System.IO; @@ -15,6 +17,8 @@ public partial class GenericShip private Transform shipAllParts; private Transform modelCenter; + public AiPlansStorage AiPlans = new AiPlansStorage(); + private string originalSkinName; protected string SpecialModel; @@ -399,8 +403,6 @@ public void HighlightThisSelected() projector.GetComponent().material = (Material)Resources.Load("Projectors/Materials/SelectionThisProjector", typeof(Material)); } - - public void HighlightAnyHovered() { Transform projector = GetSelectionProjector(); @@ -576,4 +578,98 @@ public string FixTypeName(string inputName) } + public class AiPlansStorage + { + private List PlansList = new List(); + public bool shipHasManeuvered = false; + + public AiSinglePlan GetPlannedAction() + { + if (PlansList.Count != 0) + { + OrderByPriority(); + return PlansList.First(); + } + else + { + return null; + } + } + + public int GetActionsCount() + { + return PlansList.Count(); + } + + public AiSinglePlan GetPlanByActionName(string actionName) + { + AiSinglePlan chosenPlan = null; + if (PlansList.Count != 0) + { + foreach (AiSinglePlan plan in PlansList) + { + if (plan.currentAction.Name == actionName) + { + chosenPlan = plan; + break; + } + } + } + return chosenPlan; + } + + public void OrderByPriority() + { + // Put the highest priority action first. + PlansList.OrderByDescending(plan => plan.Priority); + } + + public void AddPlan(AiSinglePlan newPlan) + { + PlansList.Add(newPlan); + } + + public void RemovePlan(AiSinglePlan Plan) + { + if (PlansList.Count > 0) + { + PlansList.Remove(Plan); + } + } + + public void ClearPlans() + { + PlansList.Clear(); + } + } + + public class AiSinglePlan + { + public int Priority = 0; + public string actionName; + public bool isRedAction = false; + public GenericAction currentAction = null; + public GenericMovement currentActionMove = null; + private List preferredTargets = new List(); + + public void AddTarget(GenericShip newTarget) + { + preferredTargets.Add(newTarget); + } + + public void RemoveTarget(GenericShip ship) + { + preferredTargets.Remove(ship); + } + + public void ClearTargetList() + { + preferredTargets.Clear(); + } + + public GenericShip GetFirstTarget() + { + return preferredTargets.First(); + } + } }