v0.14.6.0
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract class ShipIssueWorker
|
||||
{
|
||||
public const float MaxImportance = 100f;
|
||||
public const float MinImportance = 0f;
|
||||
public Order SuggestedOrderPrefab { get; }
|
||||
|
||||
private float importance;
|
||||
public float Importance
|
||||
{
|
||||
get
|
||||
{
|
||||
return importance;
|
||||
}
|
||||
set
|
||||
{
|
||||
importance = MathHelper.Clamp(value, MinImportance, MaxImportance);
|
||||
}
|
||||
}
|
||||
public float CurrentRedundancy { get; set; }
|
||||
|
||||
public readonly ShipCommandManager shipCommandManager;
|
||||
public string Option { get; set; }
|
||||
public Character OrderedCharacter { get; set; }
|
||||
public Order CurrentOrder { get; private set; }
|
||||
public ItemComponent TargetItemComponent { get; protected set; }
|
||||
public Item TargetItem { get; protected set; }
|
||||
public bool Active { get; protected set; } = true; // used to turn off the instance if errors are detected
|
||||
|
||||
protected virtual Character CommandingCharacter => shipCommandManager.character;
|
||||
public virtual float TimeSinceLastAttempt { get; set; }
|
||||
public virtual float RedundantIssueModifier => 0.5f;
|
||||
public virtual bool StopDuringEmergency => true; // limit certain issue assessments when invaded by the enemies
|
||||
public virtual bool AllowEasySwitching => false;
|
||||
|
||||
public ShipIssueWorker(ShipCommandManager shipCommandManager, Order suggestedOrderPrefab, string option = null)
|
||||
{
|
||||
this.shipCommandManager = shipCommandManager;
|
||||
SuggestedOrderPrefab = suggestedOrderPrefab;
|
||||
Option = option;
|
||||
}
|
||||
|
||||
public void SetOrder(Character orderedCharacter)
|
||||
{
|
||||
OrderedCharacter = orderedCharacter;
|
||||
if (orderedCharacter != CommandingCharacter)
|
||||
{
|
||||
CommandingCharacter.Speak(SuggestedOrderPrefab.GetChatMessage(OrderedCharacter.Name, "", false));
|
||||
}
|
||||
|
||||
// not sure if new orders are supposed to be created each time. TODO m61: check later
|
||||
CurrentOrder = new Order(SuggestedOrderPrefab, TargetItem, TargetItemComponent, CommandingCharacter);
|
||||
OrderedCharacter.SetOrder(CurrentOrder, Option, priority: 3, CommandingCharacter, CommandingCharacter != OrderedCharacter);
|
||||
TimeSinceLastAttempt = 0f;
|
||||
}
|
||||
|
||||
public void RemoveOrder()
|
||||
{
|
||||
OrderedCharacter = null;
|
||||
CurrentOrder = null;
|
||||
}
|
||||
|
||||
protected virtual bool IsIssueViable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public float CalculateImportance(bool isEmergency)
|
||||
{
|
||||
Importance = 0f; // reset anything that needs resetting
|
||||
|
||||
if (!Active)
|
||||
{
|
||||
return Importance;
|
||||
}
|
||||
|
||||
Active = IsIssueViable();
|
||||
|
||||
if (isEmergency && StopDuringEmergency)
|
||||
{
|
||||
return Importance;
|
||||
}
|
||||
|
||||
CalculateImportanceSpecific();
|
||||
|
||||
// if there are other orders of the same type already being attended to, such as fixing leaks
|
||||
// reduce the relative importance of this issue
|
||||
CurrentRedundancy = 1f;
|
||||
foreach (ShipIssueWorker shipIssueWorker in shipCommandManager.ShipIssueWorkers)
|
||||
{
|
||||
if (shipIssueWorker.GetType() == GetType() && shipIssueWorker != this && shipIssueWorker.OrderAttendedTo())
|
||||
{
|
||||
CurrentRedundancy *= RedundantIssueModifier;
|
||||
}
|
||||
}
|
||||
Importance *= CurrentRedundancy;
|
||||
|
||||
return Importance;
|
||||
}
|
||||
|
||||
public bool OrderAttendedTo(float timeSinceLastCheck = 0f)
|
||||
{
|
||||
if (!HumanAIController.IsActive(OrderedCharacter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// accept only the highest priority order
|
||||
if (CurrentOrder != null && OrderedCharacter.GetCurrentOrderWithTopPriority()?.Order != CurrentOrder)
|
||||
{
|
||||
#if DEBUG
|
||||
ShipCommandManager.ShipCommandLog($"Order {CurrentOrder.Name} did not match current order for character {OrderedCharacter} in {this}");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!shipCommandManager.AbleToTakeOrder(OrderedCharacter))
|
||||
{
|
||||
#if DEBUG
|
||||
ShipCommandManager.ShipCommandLog(OrderedCharacter + " was unable to perform assigned order in " + this);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public abstract void CalculateImportanceSpecific();
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class ShipGlobalIssueFixLeaks : ShipGlobalIssue
|
||||
{
|
||||
readonly List<float> hullSeverities = new List<float>();
|
||||
public ShipGlobalIssueFixLeaks(ShipCommandManager shipCommandManager) : base(shipCommandManager) { }
|
||||
public override void CalculateGlobalIssue()
|
||||
{
|
||||
hullSeverities.Clear();
|
||||
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
{
|
||||
if (AIObjectiveFixLeaks.IsValidTarget(gap, shipCommandManager.character))
|
||||
{
|
||||
hullSeverities.Add(AIObjectiveFixLeaks.GetLeakSeverity(gap));
|
||||
}
|
||||
}
|
||||
|
||||
float averagePercentage = 0f;
|
||||
if (hullSeverities.Any())
|
||||
{
|
||||
hullSeverities.Sort();
|
||||
averagePercentage = hullSeverities.TakeLast(3).Average(); // get the 3 most damaged items on the ship and get their average
|
||||
}
|
||||
GlobalImportance = averagePercentage;
|
||||
}
|
||||
}
|
||||
|
||||
class ShipIssueWorkerFixLeaks : ShipIssueWorkerGlobal
|
||||
{
|
||||
public override bool StopDuringEmergency => false;
|
||||
public ShipIssueWorkerFixLeaks(ShipCommandManager shipCommandManager, Order order, ShipGlobalIssueFixLeaks shipGlobalIssueFixLeaks) : base(shipCommandManager, order, shipGlobalIssueFixLeaks) { }
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract class ShipGlobalIssue
|
||||
{
|
||||
public float GlobalImportance { get; set; }
|
||||
|
||||
protected ShipCommandManager shipCommandManager;
|
||||
public ShipGlobalIssue(ShipCommandManager shipCommandManager)
|
||||
{
|
||||
this.shipCommandManager = shipCommandManager;
|
||||
}
|
||||
public abstract void CalculateGlobalIssue();
|
||||
}
|
||||
|
||||
abstract class ShipIssueWorkerGlobal : ShipIssueWorker
|
||||
{
|
||||
private readonly ShipGlobalIssue shipGlobalIssue;
|
||||
|
||||
public ShipIssueWorkerGlobal(ShipCommandManager shipCommandManager, Order suggestedOrderPrefab, ShipGlobalIssue shipGlobalIssue) : base (shipCommandManager, suggestedOrderPrefab)
|
||||
{
|
||||
this.shipGlobalIssue = shipGlobalIssue;
|
||||
}
|
||||
|
||||
public override void CalculateImportanceSpecific() // importances for global issues are precalculated, so that they don't need to be calculated per each attending character
|
||||
{
|
||||
Importance = shipGlobalIssue.GlobalImportance;
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract class ShipIssueWorkerItem : ShipIssueWorker
|
||||
{
|
||||
public ShipIssueWorkerItem(ShipCommandManager shipCommandManager, Order order, Item targetItem, ItemComponent targetItemComponent, string option = null) : base(shipCommandManager, order, option)
|
||||
{
|
||||
TargetItemComponent = targetItemComponent;
|
||||
TargetItem = targetItem;
|
||||
}
|
||||
|
||||
protected override bool IsIssueViable()
|
||||
{
|
||||
if (TargetItemComponent == null)
|
||||
{
|
||||
DebugConsole.ThrowError("TargetItemComponent was null in " + this);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TargetItem == null)
|
||||
{
|
||||
DebugConsole.ThrowError("TargetItem was null in " + this);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class ShipIssueWorkerOperateWeapons : ShipIssueWorkerItem
|
||||
{
|
||||
public override float RedundantIssueModifier => 0.65f;
|
||||
private readonly List<float> targetingImportances = new List<float>();
|
||||
|
||||
public override bool AllowEasySwitching => true;
|
||||
|
||||
public ShipIssueWorkerOperateWeapons(ShipCommandManager shipCommandManager, Order order, Item targetItem, ItemComponent targetItemComponent) : base(shipCommandManager, order, targetItem, targetItemComponent) { }
|
||||
|
||||
float GetTargetingImportance(Entity entity)
|
||||
{
|
||||
float currentDistanceToEnemy = Vector2.Distance(entity.WorldPosition, TargetItem.WorldPosition);
|
||||
return MathHelper.Clamp(100 - (currentDistanceToEnemy / 100f), MinImportance, MaxImportance);
|
||||
}
|
||||
|
||||
public override void CalculateImportanceSpecific()
|
||||
{
|
||||
if (TargetItemComponent is Turret turret && !turret.HasPowerToShoot()) { return; }
|
||||
|
||||
targetingImportances.Clear();
|
||||
foreach (Character character in shipCommandManager.EnemyCharacters)
|
||||
{
|
||||
targetingImportances.Add(GetTargetingImportance(character));
|
||||
}
|
||||
// there should maybe be additional logic for targeting and destroying spires, because they currently cause some issues with pathing
|
||||
|
||||
if (targetingImportances.Any())
|
||||
{
|
||||
targetingImportances.Sort();
|
||||
Importance = targetingImportances.TakeLast(3).Average();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class ShipIssueWorkerPowerUpReactor : ShipIssueWorkerItem
|
||||
{
|
||||
public ShipIssueWorkerPowerUpReactor(ShipCommandManager shipCommandManager, Order order, Item targetItem, ItemComponent targetItemComponent, string option) : base(shipCommandManager, order, targetItem, targetItemComponent, option)
|
||||
{
|
||||
}
|
||||
|
||||
public override void CalculateImportanceSpecific()
|
||||
{
|
||||
if (TargetItem.Condition <= 0f) { return; }
|
||||
|
||||
if (TargetItemComponent is Reactor reactor && -reactor.CurrPowerConsumption < float.Epsilon)
|
||||
{
|
||||
Importance = 40f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class ShipGlobalIssueRepairSystems : ShipGlobalIssue
|
||||
{
|
||||
readonly List<Item> itemsNeedingRepair = new List<Item>();
|
||||
|
||||
public ShipGlobalIssueRepairSystems(ShipCommandManager shipCommandManager) : base(shipCommandManager) { }
|
||||
|
||||
public override void CalculateGlobalIssue()
|
||||
{
|
||||
itemsNeedingRepair.Clear();
|
||||
|
||||
foreach (Item item in shipCommandManager.CommandedSubmarine.GetItems(true))
|
||||
{
|
||||
if (!AIObjectiveRepairItems.ViableForRepair(item, shipCommandManager.character, shipCommandManager.character.AIController as HumanAIController)) { continue; }
|
||||
if (AIObjectiveRepairItems.NearlyFullCondition(item)) { continue; }
|
||||
itemsNeedingRepair.Add(item);
|
||||
// merged this logic with AIObjectiveRepairItems
|
||||
}
|
||||
|
||||
if (itemsNeedingRepair.Any())
|
||||
{
|
||||
itemsNeedingRepair.Sort((x, y) => y.ConditionPercentage.CompareTo(x.ConditionPercentage));
|
||||
float modifiedPercentage = itemsNeedingRepair.TakeLast(3).Average(x => x.ConditionPercentage) * 0.6f + itemsNeedingRepair.TakeLast(10).Average(x => x.ConditionPercentage) * 0.4f;
|
||||
// calculate a modified percentage with the most damaged items, with 60% the weight given to the top 3 damaged and the remaining given to top 10
|
||||
GlobalImportance = 100 - modifiedPercentage;
|
||||
}
|
||||
// this system works reasonably well, though it could give extra importance to repairing critical items like reactors and junction boxes
|
||||
}
|
||||
}
|
||||
|
||||
class ShipIssueWorkerRepairSystems : ShipIssueWorkerGlobal // this class could be removed, but it might need special behavior later
|
||||
{
|
||||
public ShipIssueWorkerRepairSystems(ShipCommandManager shipCommandManager, Order order, ShipGlobalIssueRepairSystems shipGlobalIssueRepairSystems) : base(shipCommandManager, order, shipGlobalIssueRepairSystems)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class ShipIssueWorkerSteer : ShipIssueWorkerItem
|
||||
{
|
||||
// The AI could be set to steer automatically through a specialized job or autonomous objectives
|
||||
// but the logic involved doesn't really allow that without some annoyingly specific changes
|
||||
// hence the AI will command itself to steer if steering is not being taken care of or the target location is wrong
|
||||
public ShipIssueWorkerSteer(ShipCommandManager shipCommandManager, Order order, Item targetItem, ItemComponent targetItemComponent, string option) : base(shipCommandManager, order, targetItem, targetItemComponent, option) { }
|
||||
public override void CalculateImportanceSpecific()
|
||||
{
|
||||
if (shipCommandManager.NavigationState == ShipCommandManager.NavigationStates.Inactive) { return; }
|
||||
if (TargetItemComponent is Powered powered && powered.Voltage <= powered.MinVoltage) { return; }
|
||||
if (TargetItem.Condition <= 0f) { return; }
|
||||
|
||||
Importance = 70f;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user