(43c3787ae) Refactor AIObjectiveRescue and remove ShouldInterruptSubObjective property. Not yet tested.
This commit is contained in:
@@ -77,13 +77,6 @@ namespace Barotrauma
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"Removing subobjective {subObjective.DebugTag} of {DebugTag}, because it cannot be completed.");
|
||||
#endif
|
||||
subObjectives.Remove(subObjective);
|
||||
}
|
||||
else if (subObjective.ShouldInterruptSubObjective(subObjective))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"Removing subobjective {subObjective.DebugTag} of {DebugTag}, because it is interrupted.");
|
||||
#endif
|
||||
subObjectives.Remove(subObjective);
|
||||
}
|
||||
@@ -199,9 +192,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
protected virtual bool ShouldInterruptSubObjective(AIObjective subObjective) => false;
|
||||
|
||||
public virtual void OnSelected()
|
||||
{
|
||||
// Should we reset steering here?
|
||||
|
||||
@@ -125,6 +125,31 @@ namespace Barotrauma
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
}
|
||||
Vector2 gapDiff = Leak.WorldPosition - character.WorldPosition;
|
||||
// TODO: use the collider size/reach?
|
||||
if (!character.AnimController.InWater && Math.Abs(gapDiff.X) < 100 && gapDiff.Y < 0.0f && gapDiff.Y > -150)
|
||||
{
|
||||
HumanAIController.AnimController.Crouching = true;
|
||||
}
|
||||
float reach = ConvertUnits.ToSimUnits(repairTool.Range);
|
||||
bool canOperate = ConvertUnits.ToSimUnits(gapDiff.Length()) < reach;
|
||||
if (canOperate)
|
||||
{
|
||||
TryAddSubObjective(ref operateObjective, () => new AIObjectiveOperateItem(repairTool, character, objectiveManager, option: "", requireEquip: true, operateTarget: Leak));
|
||||
}
|
||||
else
|
||||
{
|
||||
TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character, objectiveManager) { CloseEnough = reach * 0.75f });
|
||||
}
|
||||
var repairTool = weldingTool.GetComponent<RepairTool>();
|
||||
if (repairTool == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
|
||||
@@ -74,21 +74,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (objectiveManager.CurrentObjective == this)
|
||||
{
|
||||
if (randomTimer > 0)
|
||||
{
|
||||
randomTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsCompleted() => false;
|
||||
public override bool CanBeCompleted => true;
|
||||
|
||||
|
||||
@@ -87,6 +87,10 @@ namespace Barotrauma
|
||||
{
|
||||
isCompleted = true;
|
||||
}
|
||||
if (component.AIOperate(deltaTime, character, this))
|
||||
{
|
||||
isCompleted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
// TODO: refactor
|
||||
class AIObjectiveRescue : AIObjective
|
||||
{
|
||||
public override string DebugTag => "rescue";
|
||||
@@ -21,21 +20,7 @@ namespace Barotrauma
|
||||
|
||||
private float treatmentTimer;
|
||||
|
||||
public override bool CanBeCompleted
|
||||
{
|
||||
get
|
||||
{
|
||||
if (targetCharacter.Removed ||
|
||||
targetCharacter.IsDead ||
|
||||
targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.VitalityThreshold)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (goToObjective != null && !goToObjective.CanBeCompleted) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool CanBeCompleted => base.CanBeCompleted && AIObjectiveRescueAll.IsValidTarget(targetCharacter, character);
|
||||
|
||||
public AIObjectiveRescue(Character character, Character targetCharacter, AIObjectiveManager objectiveManager, float priorityModifier = 1)
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
@@ -52,14 +37,19 @@ namespace Barotrauma
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
//target in water -> move to a dry place first
|
||||
if (targetCharacter.AnimController.InWater)
|
||||
// Target is not in a safe place -> Move to a safe place first
|
||||
if (HumanAIController.GetHullSafety(targetCharacter.CurrentHull, targetCharacter) < HumanAIController.HULL_SAFETY_THRESHOLD)
|
||||
{
|
||||
if (character.SelectedCharacter != targetCharacter)
|
||||
{
|
||||
// Go to the target and select it
|
||||
if (!character.CanInteractWith(targetCharacter))
|
||||
{
|
||||
AddSubObjective(goToObjective = new AIObjectiveGoTo(targetCharacter, character, objectiveManager));
|
||||
if (goToObjective != null && goToObjective.Target != targetCharacter)
|
||||
{
|
||||
goToObjective = null;
|
||||
}
|
||||
TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(targetCharacter, character, objectiveManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -68,15 +58,28 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSubObjective(new AIObjectiveFindSafety(character, objectiveManager));
|
||||
// Drag the character into safety
|
||||
if (goToObjective != null && goToObjective.Target == targetCharacter)
|
||||
{
|
||||
goToObjective = null;
|
||||
}
|
||||
var findSafety = objectiveManager.GetObjective<AIObjectiveFindSafety>();
|
||||
if (findSafety == null)
|
||||
{
|
||||
// Ensure that we have the find safety objective (should always be the case)
|
||||
objectiveManager.AddObjective(new AIObjectiveFindSafety(character, objectiveManager));
|
||||
}
|
||||
TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(findSafety.FindBestHull(), character, objectiveManager));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//target not in water -> we can start applying treatment
|
||||
if (subObjectives.Any()) { return; }
|
||||
|
||||
// We can start applying treatment
|
||||
if (!character.CanInteractWith(targetCharacter))
|
||||
{
|
||||
AddSubObjective(goToObjective = new AIObjectiveGoTo(targetCharacter, character, objectiveManager));
|
||||
TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(targetCharacter, character, objectiveManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -87,32 +90,12 @@ namespace Barotrauma
|
||||
null, 1.0f,
|
||||
"foundunconscioustarget" + targetCharacter.Name, 60.0f);
|
||||
}
|
||||
|
||||
character.SelectCharacter(targetCharacter);
|
||||
GiveTreatment(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove and replace with the priority system
|
||||
protected override bool ShouldInterruptSubObjective(AIObjective subObjective)
|
||||
{
|
||||
if (subObjective is AIObjectiveFindSafety)
|
||||
{
|
||||
if (character.SelectedCharacter != targetCharacter) return true;
|
||||
if (character.AnimController.InWater || targetCharacter.AnimController.InWater) return false;
|
||||
|
||||
foreach (Limb limb in targetCharacter.AnimController.Limbs)
|
||||
{
|
||||
if (!Submarine.RectContains(targetCharacter.CurrentHull.WorldRect, limb.WorldPosition)) return false;
|
||||
}
|
||||
|
||||
return !character.AnimController.InWater && !targetCharacter.AnimController.InWater &&
|
||||
HumanAIController.GetHullSafety(character.CurrentHull, character) > HumanAIController.HULL_SAFETY_THRESHOLD;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: consider optimizing a bit
|
||||
private void GiveTreatment(float deltaTime)
|
||||
{
|
||||
if (treatmentTimer > 0.0f)
|
||||
@@ -129,7 +112,6 @@ namespace Barotrauma
|
||||
{
|
||||
return Math.Sign(a2.GetVitalityDecrease(targetCharacter.CharacterHealth) - a1.GetVitalityDecrease(targetCharacter.CharacterHealth));
|
||||
});
|
||||
|
||||
//check if we already have a suitable treatment for any of the afflictions
|
||||
foreach (Affliction affliction in allAfflictions)
|
||||
{
|
||||
@@ -144,7 +126,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//didn't have any suitable treatments available, try to find some medical items
|
||||
HashSet<string> suitableItemIdentifiers = new HashSet<string>();
|
||||
foreach (Affliction affliction in allAfflictions)
|
||||
@@ -167,9 +148,8 @@ namespace Barotrauma
|
||||
itemNameList.Add(itemPrefab.Name);
|
||||
}
|
||||
//only list the first 4 items
|
||||
if (itemNameList.Count >= 4) break;
|
||||
if (itemNameList.Count >= 4) { break; }
|
||||
}
|
||||
|
||||
if (itemNameList.Count > 0)
|
||||
{
|
||||
string itemListStr = "";
|
||||
@@ -186,30 +166,29 @@ namespace Barotrauma
|
||||
.Replace("[treatmentlist]", itemListStr),
|
||||
null, 2.0f, "listrequiredtreatments" + targetCharacter.Name, 60.0f);
|
||||
}
|
||||
|
||||
character.DeselectCharacter();
|
||||
AddSubObjective(new AIObjectiveGetItem(character, suitableItemIdentifiers.ToArray(), objectiveManager, equip: true));
|
||||
}
|
||||
|
||||
character.AnimController.Anim = AnimController.Animation.CPR;
|
||||
}
|
||||
|
||||
private void ApplyTreatment(Affliction affliction, Item item)
|
||||
{
|
||||
var targetLimb = targetCharacter.CharacterHealth.GetAfflictionLimb(affliction);
|
||||
|
||||
bool remove = false;
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (!ic.HasRequiredContainedItems(addMessage: false)) continue;
|
||||
if (!ic.HasRequiredContainedItems(addMessage: false)) { continue; }
|
||||
#if CLIENT
|
||||
ic.PlaySound(ActionType.OnUse, character.WorldPosition, character);
|
||||
#endif
|
||||
ic.WasUsed = true;
|
||||
ic.ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb);
|
||||
if (ic.DeleteOnUse) remove = true;
|
||||
if (ic.DeleteOnUse)
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove)
|
||||
{
|
||||
Entity.Spawner?.AddToRemoveQueue(item);
|
||||
@@ -218,29 +197,26 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
bool isCompleted =
|
||||
targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.VitalityThreshold;
|
||||
|
||||
bool isCompleted = targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.VitalityThreshold;
|
||||
if (isCompleted)
|
||||
{
|
||||
character?.Speak(TextManager.Get("DialogTargetHealed").Replace("[targetname]", targetCharacter.Name),
|
||||
null, 1.0f, "targethealed" + targetCharacter.Name, 60.0f);
|
||||
}
|
||||
|
||||
return isCompleted || targetCharacter.IsDead;
|
||||
return isCompleted || targetCharacter.Removed || targetCharacter.IsDead;
|
||||
}
|
||||
|
||||
public override float GetPriority()
|
||||
{
|
||||
// TODO: review
|
||||
if (targetCharacter.AnimController.CurrentHull == null || targetCharacter.IsDead) { return 0.0f; }
|
||||
|
||||
Vector2 diff = targetCharacter.WorldPosition - character.WorldPosition;
|
||||
float distance = Math.Abs(diff.X) + Math.Abs(diff.Y);
|
||||
|
||||
float vitalityFactor = (targetCharacter.MaxVitality - targetCharacter.Vitality) / targetCharacter.MaxVitality;
|
||||
|
||||
return 1000.0f * vitalityFactor / distance;
|
||||
if (targetCharacter.CurrentHull == null || targetCharacter.IsDead) { return 0; ; }
|
||||
// Don't go into rooms that have enemies
|
||||
if (Character.CharacterList.Any(c => c.CurrentHull == targetCharacter.CurrentHull && !HumanAIController.IsFriendly(c))) { return 0; }
|
||||
// Vertical distance matters more than horizontal (climbing up/down is harder than moving horizontally)
|
||||
float dist = Math.Abs(character.WorldPosition.X - targetCharacter.WorldPosition.X) + Math.Abs(character.WorldPosition.Y - targetCharacter.WorldPosition.Y) * 2.0f;
|
||||
float distanceFactor = MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 10000, dist));
|
||||
float vitalityFactor = AIObjectiveRescueAll.GetVitalityFactor(targetCharacter);
|
||||
float devotion = Math.Max(Priority, 10) / 100;
|
||||
return MathHelper.Lerp(0, 100, MathHelper.Clamp(devotion + vitalityFactor * distanceFactor, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user