(c3a729b34) Fix ai reporting only working if there's someone with the appropriate objective. Use the target's hull instead of using the reporter's hull. Take bleeding into account when filtering rescue targets.

This commit is contained in:
Joonas Rikkonen
2019-05-16 06:54:49 +03:00
parent 4c4cac9c39
commit 81fe275299
13 changed files with 140 additions and 216 deletions
@@ -121,90 +121,7 @@ namespace Barotrauma
MainLimb.PullJointWorldAnchorB = Collider.SimPosition; MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
MainLimb.PullJointEnabled = true; MainLimb.PullJointEnabled = true;
} }
character.SelectedConstruction = character.MemState[0].SelectedItem;
} }
if (character.MemState[0].Animation == AnimController.Animation.CPR)
{
character.AnimController.Anim = AnimController.Animation.CPR;
}
else if (character.AnimController.Anim == AnimController.Animation.CPR)
{
character.AnimController.Anim = AnimController.Animation.None;
}
Vector2 newVelocity = Collider.LinearVelocity;
Vector2 newPosition = Collider.SimPosition;
float newRotation = Collider.Rotation;
float newAngularVelocity = Collider.AngularVelocity;
Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);
newVelocity = newVelocity.ClampLength(100.0f);
if (!MathUtils.IsValid(newVelocity)) { newVelocity = Vector2.Zero; }
overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero;
Collider.LinearVelocity = newVelocity;
Collider.AngularVelocity = newAngularVelocity;
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
float errorTolerance = character.AllowInput ? 0.01f : 0.2f;
if (distSqrd > errorTolerance)
{
if (distSqrd > 10.0f || !character.AllowInput)
{
Collider.TargetRotation = newRotation;
SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false);
}
else
{
Collider.TargetRotation = newRotation;
Collider.TargetPosition = newPosition;
Collider.MoveToTargetPosition(true);
}
}
//unconscious/dead characters can't correct their position using AnimController movement
// -> we need to correct it manually
if (!character.AllowInput)
{
float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition);
float mainLimbErrorTolerance = 0.1f;
//if the main limb is roughly at the correct position and the collider isn't moving (much at least),
//don't attempt to correct the position.
if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f)
{
MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
MainLimb.PullJointEnabled = true;
}
}
}
character.MemLocalState.Clear();
}
else
{
//remove states with a timestamp (there may still timestamp-based states
//in the list if the controlled character switches from timestamp-based interpolation to ID-based)
character.MemState.RemoveAll(m => m.Timestamp > 0.0f);
for (int i = 0; i < character.MemLocalState.Count; i++)
{
if (character.Submarine == null)
{
//transform in-sub coordinates to outside coordinates
if (character.MemLocalState[i].Position.Y > lowestSubPos)
{
character.MemLocalState[i].TransformInToOutside();
}
}
else if (currentHull?.Submarine != null)
{
//transform outside coordinates to in-sub coordinates
if (character.MemLocalState[i].Position.Y < lowestSubPos)
{
character.MemLocalState[i].TransformOutToInside(currentHull.Submarine);
}
}
} }
character.MemLocalState.Clear(); character.MemLocalState.Clear();
} }
@@ -724,6 +724,8 @@ namespace Barotrauma
private GUILayoutGroup subPreviewContainer; private GUILayoutGroup subPreviewContainer;
private GUILayoutGroup subPreviewContainer;
private GUIButton loadGameButton; private GUIButton loadGameButton;
public Action<Submarine, string, string> StartNewGame; public Action<Submarine, string, string> StartNewGame;
@@ -118,7 +118,6 @@ namespace Barotrauma
objectiveManager.SortObjectives(); objectiveManager.SortObjectives();
sortTimer = sortObjectiveInterval; sortTimer = sortObjectiveInterval;
} }
if (reactTimer > 0.0f) if (reactTimer > 0.0f)
{ {
reactTimer -= deltaTime; reactTimer -= deltaTime;
@@ -374,14 +373,38 @@ namespace Barotrauma
{ {
foreach (var hull in VisibleHulls) foreach (var hull in VisibleHulls)
{ {
foreach (Character c in Character.CharacterList)
{
if (c.CurrentHull != hull) { continue; }
if (AIObjectiveFightIntruders.IsValidTarget(c, Character))
{
AddTargets<AIObjectiveFightIntruders, Character>(Character, c);
if (newOrder == null)
{
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
newOrder = new Order(orderPrefab, c.CurrentHull, null);
}
}
}
if (AIObjectiveExtinguishFires.IsValidTarget(hull, Character)) if (AIObjectiveExtinguishFires.IsValidTarget(hull, Character))
{ {
if (AddTargets<AIObjectiveExtinguishFires, Hull>(Character, hull)) AddTargets<AIObjectiveExtinguishFires, Hull>(Character, hull);
if (newOrder == null)
{ {
if (hull == Character.CurrentHull) var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportfire");
newOrder = new Order(orderPrefab, hull, null);
}
}
foreach (Character c in Character.CharacterList)
{
if (c.CurrentHull != hull) { continue; }
if (AIObjectiveRescueAll.IsValidTarget(c, Character))
{
AddTargets<AIObjectiveRescueAll, Character>(c, Character);
if (newOrder == null)
{ {
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportfire"); var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
newOrder = new Order(orderPrefab, Character.CurrentHull, null); newOrder = new Order(orderPrefab, c.CurrentHull, null);
} }
} }
} }
@@ -389,13 +412,11 @@ namespace Barotrauma
{ {
if (AIObjectiveFixLeaks.IsValidTarget(gap, Character)) if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
{ {
if (AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap)) AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap);
if (newOrder == null)
{ {
if (hull == Character.CurrentHull) var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
{ newOrder = new Order(orderPrefab, hull, null);
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
}
} }
} }
} }
@@ -405,39 +426,14 @@ namespace Barotrauma
if (AIObjectiveRepairItems.IsValidTarget(item, Character)) if (AIObjectiveRepairItems.IsValidTarget(item, Character))
{ {
if (item.Repairables.All(r => item.Condition > r.ShowRepairUIThreshold)) { continue; } if (item.Repairables.All(r => item.Condition > r.ShowRepairUIThreshold)) { continue; }
if (AddTargets<AIObjectiveRepairItems, Item>(Character, item)) AddTargets<AIObjectiveRepairItems, Item>(Character, item);
if (newOrder == null)
{ {
if (hull == Character.CurrentHull) var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbrokendevices");
{ newOrder = new Order(orderPrefab, item.CurrentHull, item.Repairables?.FirstOrDefault());
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbrokendevices");
newOrder = new Order(orderPrefab, Character.CurrentHull, item.Repairables?.FirstOrDefault());
}
} }
} }
} }
foreach (Character c in Character.CharacterList)
{
if (c.CurrentHull != hull) { continue; }
if (AIObjectiveFightIntruders.IsValidTarget(c, Character))
{
if (AddTargets<AIObjectiveFightIntruders, Character>(Character, c))
{
if (hull == Character.CurrentHull)
{
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
}
}
}
}
}
if (Character.Bleeding > 1.0f || Character.Vitality < Character.MaxVitality * 0.1f)
{
if (AddTargets<AIObjectiveRescueAll, Character>(Character, Character))
{
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
}
} }
} }
if (newOrder != null) if (newOrder != null)
@@ -465,6 +465,32 @@ namespace Barotrauma
{ {
#if DEBUG #if DEBUG
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool"); 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 * 1.5f;
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 });
}
if (subObjectives.Any()) { return; }
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 #endif
abandon = true; abandon = true;
return; return;
@@ -89,6 +89,21 @@ 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 IsCompleted() => false;
public override bool CanBeCompleted => true; public override bool CanBeCompleted => true;
@@ -849,6 +849,10 @@ namespace Barotrauma
{ {
isCompleted = true; isCompleted = true;
} }
if (component.AIOperate(deltaTime, character, this))
{
isCompleted = true;
}
} }
else else
{ {
@@ -23,6 +23,12 @@ namespace Barotrauma
public AIObjectiveRescue(Character character, Character targetCharacter, AIObjectiveManager objectiveManager, float priorityModifier = 1) public AIObjectiveRescue(Character character, Character targetCharacter, AIObjectiveManager objectiveManager, float priorityModifier = 1)
: base(character, objectiveManager, priorityModifier) : base(character, objectiveManager, priorityModifier)
{ {
if (targetCharacter != character)
{
// TODO: enable healing self too
abandon = true;
return;
}
this.targetCharacter = targetCharacter; this.targetCharacter = targetCharacter;
} }
@@ -201,7 +207,7 @@ namespace Barotrauma
public override bool IsCompleted() public override bool IsCompleted()
{ {
bool isCompleted = targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager); bool isCompleted = targetCharacter.Bleeding <= 0 && targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager);
if (isCompleted) if (isCompleted)
{ {
character.Speak(TextManager.Get("DialogTargetHealed").Replace("[targetname]", targetCharacter.Name), character.Speak(TextManager.Get("DialogTargetHealed").Replace("[targetname]", targetCharacter.Name),
@@ -9,7 +9,7 @@ namespace Barotrauma
public override string DebugTag => "rescue all"; public override string DebugTag => "rescue all";
public override bool ForceRun => true; public override bool ForceRun => true;
private const float vitalityThreshold = 0.85f; private const float vitalityThreshold = 0.8f;
private const float vitalityThresholdForOrders = 0.95f; private const float vitalityThresholdForOrders = 0.95f;
public static float GetVitalityThreshold(AIObjectiveManager manager) => manager.CurrentOrder is AIObjectiveRescueAll ? vitalityThresholdForOrders : vitalityThreshold; public static float GetVitalityThreshold(AIObjectiveManager manager) => manager.CurrentOrder is AIObjectiveRescueAll ? vitalityThresholdForOrders : vitalityThreshold;
@@ -35,10 +35,9 @@ namespace Barotrauma
public static bool IsValidTarget(Character target, Character character) public static bool IsValidTarget(Character target, Character character)
{ {
if (target == null || target.IsDead || target.Removed) { return false; } if (target == null || target.IsDead || target.Removed) { return false; }
if (target == character) { return false; } // TODO: enable healing self
if (!HumanAIController.IsFriendly(character, target)) { return false; } if (!HumanAIController.IsFriendly(character, target)) { return false; }
if (!(character.AIController is HumanAIController humanAI)) { return false; } if (!(character.AIController is HumanAIController humanAI)) { return false; }
if (target.Vitality / target.MaxVitality > GetVitalityThreshold(humanAI.ObjectiveManager)) { return false; } if (target.Bleeding < 1 && target.Vitality / target.MaxVitality > GetVitalityThreshold(humanAI.ObjectiveManager)) { return false; }
if (target.Submarine == null) { return false; } if (target.Submarine == null) { return false; }
if (target.Submarine.TeamID != character.Submarine.TeamID) { return false; } if (target.Submarine.TeamID != character.Submarine.TeamID) { return false; }
if (target.CurrentHull == null) { return false; } if (target.CurrentHull == null) { return false; }
@@ -1145,24 +1145,6 @@ namespace Barotrauma
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff; SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
} }
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
{
//apply some smoothing to the cursor positions of remote players when playing as a client
//to make aiming look a little less choppy
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
}
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
{
//apply some smoothing to the cursor positions of remote players when playing as a client
//to make aiming look a little less choppy
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
}
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer) if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
{ {
if (speedMultipliers.Count == 0) return 1f; if (speedMultipliers.Count == 0) return 1f;
@@ -943,6 +943,25 @@ namespace Barotrauma.Items.Components
} }
} }
if (targetItem.Prefab.DeconstructItems.Any())
{
inputContainer.Inventory.RemoveItem(targetItem);
Entity.Spawner.AddToRemoveQueue(targetItem);
MoveInputQueue();
PutItemsToLinkedContainer();
}
else
{
if (outputContainer.Inventory.Items.All(i => i != null))
{
targetItem.Drop(dropper: null);
}
else
{
outputContainer.Inventory.TryPutItem(targetItem, user: null, createNetworkEvent: true);
}
}
if (targetItem.Prefab.DeconstructItems.Any()) if (targetItem.Prefab.DeconstructItems.Any())
{ {
inputContainer.Inventory.RemoveItem(targetItem); inputContainer.Inventory.RemoveItem(targetItem);
@@ -144,6 +144,17 @@ namespace Barotrauma.Items.Components
} }
} }
public Vector2 SteeringInput
{
get { return steeringInput; }
set
{
if (!MathUtils.IsValid(value)) return;
steeringInput.X = MathHelper.Clamp(value.X, -100.0f, 100.0f);
steeringInput.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f);
}
}
public SteeringPath SteeringPath public SteeringPath SteeringPath
{ {
if (!CanBeSelected) return false; if (!CanBeSelected) return false;
@@ -164,12 +175,6 @@ namespace Barotrauma.Items.Components
set { posToMaintain = value; } set { posToMaintain = value; }
} }
public Vector2? PosToMaintain
{
get { return posToMaintain; }
set { posToMaintain = value; }
}
struct ObstacleDebugInfo struct ObstacleDebugInfo
{ {
public Vector2 Point1; public Vector2 Point1;
@@ -1139,70 +1139,6 @@ namespace Barotrauma
} }
} }
public void UpdateTransform()
{
Submarine prevSub = Submarine;
FindHull();
if (Submarine == null && prevSub != null)
{
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
}
else if (Submarine != null && prevSub == null)
{
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
}
else if (Submarine != null && prevSub != null && Submarine != prevSub)
{
body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
}
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity ||
Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity)
{
body.LinearVelocity = new Vector2(
MathHelper.Clamp(body.LinearVelocity.X, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity),
MathHelper.Clamp(body.LinearVelocity.Y, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity));
}
}
public void UpdateTransform()
{
Submarine prevSub = Submarine;
FindHull();
if (Submarine == null && prevSub != null)
{
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
}
else if (Submarine != null && prevSub == null)
{
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
}
else if (Submarine != null && prevSub != null && Submarine != prevSub)
{
body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
}
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity ||
Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity)
{
body.LinearVelocity = new Vector2(
MathHelper.Clamp(body.LinearVelocity.X, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity),
MathHelper.Clamp(body.LinearVelocity.Y, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity));
}
}
public void UpdateTransform() public void UpdateTransform()
{ {
Submarine prevSub = Submarine; Submarine prevSub = Submarine;
+18 -1
View File
@@ -83,7 +83,24 @@ namespace Barotrauma
public readonly List<Gap> ConnectedGaps = new List<Gap>(); public readonly List<Gap> ConnectedGaps = new List<Gap>();
public readonly List<Gap> ConnectedGaps = new List<Gap>(); private string roomName;
[Editable, Serialize("", true, translationTextTag: "RoomName.")]
public string RoomName
{
get { return roomName; }
set
{
if (roomName == value) { return; }
roomName = value;
DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName;
}
}
public string DisplayName
{
get;
private set;
}
private string roomName; private string roomName;
[Editable, Serialize("", true, translationTextTag: "RoomName.")] [Editable, Serialize("", true, translationTextTag: "RoomName.")]