(3a5d98b) v0.9.6.0

This commit is contained in:
Regalis
2019-12-17 14:38:24 +01:00
parent 5c95c53118
commit a3569b8bf0
95 changed files with 1579 additions and 728 deletions
@@ -21,7 +21,7 @@ namespace Barotrauma
/// <summary>
/// How long does it take for the ai target to fade out if not kept alive.
/// </summary>
public float FadeOutTime { get; private set; }
public float FadeOutTime { get; private set; } = 1;
public bool Static { get; private set; }
@@ -611,6 +611,7 @@ namespace Barotrauma
}
bool canAttack = true;
bool pursue = false;
if (IsCoolDownRunning)
{
switch (AttackingLimb.attack.AfterAttack)
@@ -623,6 +624,7 @@ namespace Barotrauma
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{
canAttack = false;
pursue = true;
}
else
{
@@ -661,6 +663,7 @@ namespace Barotrauma
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{
canAttack = false;
pursue = true;
}
else
{
@@ -853,32 +856,35 @@ namespace Barotrauma
if (pathSteering.CurrentPath != null)
{
// Attack doors
if (canAttackSub && pathSteering.CurrentPath.CurrentNode?.ConnectedDoor != null && SelectedAiTarget != pathSteering.CurrentPath.CurrentNode.ConnectedDoor.Item.AiTarget)
if (canAttackSub)
{
SelectTarget(pathSteering.CurrentPath.CurrentNode.ConnectedDoor.Item.AiTarget);
return;
// If the target is in the same hull, there shouldn't be any doors blocking the path
if (targetCharacter == null || targetCharacter.CurrentHull != Character.CurrentHull)
{
var door = pathSteering.CurrentPath.CurrentNode?.ConnectedDoor ?? pathSteering.CurrentPath.NextNode?.ConnectedDoor;
if (door != null && !door.IsOpen && door.Item.Condition > 0)
{
if (SelectedAiTarget != door.Item.AiTarget)
{
SelectTarget(door.Item.AiTarget, selectedTargetMemory.Priority);
return;
}
}
}
}
else if (canAttackSub && pathSteering.CurrentPath.NextNode?.ConnectedDoor != null && SelectedAiTarget != pathSteering.CurrentPath.NextNode.ConnectedDoor.Item.AiTarget)
// Steer towards the target if in the same room and swimming
if ((Character.AnimController.InWater || pursue) && targetCharacter != null && VisibleHulls.Contains(targetCharacter.CurrentHull))
{
SelectTarget(pathSteering.CurrentPath.NextNode.ConnectedDoor.Item.AiTarget);
return;
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(attackSimPos - steeringLimb.SimPosition));
}
else
{
// Steer towards the target if in the same room and swimming
if (Character.AnimController.InWater && targetCharacter != null && VisibleHulls.Contains(targetCharacter.CurrentHull))
SteeringManager.SteeringSeek(steerPos, 2);
// Switch to Idle when cannot reach the target and if cannot damage the walls
if ((!canAttackSub || wallTarget == null) && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
{
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(attackSimPos - steeringLimb.SimPosition));
}
else
{
SteeringManager.SteeringSeek(steerPos, 2);
// Switch to Idle when cannot reach the target and if cannot damage the walls
if ((!canAttackSub || wallTarget == null) && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
{
State = AIState.Idle;
return;
}
State = AIState.Idle;
return;
}
}
}
@@ -1148,8 +1154,8 @@ namespace Barotrauma
{
selectedTargetMemory.Priority = 0;
}
return true;
}
return true;
}
return false;
}
@@ -525,6 +525,7 @@ namespace Barotrauma
protected void ReportProblems()
{
Order newOrder = null;
Hull targetHull = null;
if (Character.CurrentHull != null)
{
foreach (var hull in VisibleHulls)
@@ -534,21 +535,21 @@ namespace Barotrauma
if (c.CurrentHull != hull || !c.Enabled) { continue; }
if (AIObjectiveFightIntruders.IsValidTarget(c, Character))
{
AddTargets<AIObjectiveFightIntruders, Character>(Character, c);
if (newOrder == null)
if (AddTargets<AIObjectiveFightIntruders, Character>(Character, c) && newOrder == null)
{
var orderPrefab = Order.GetPrefab("reportintruders");
newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
targetHull = hull;
}
}
}
if (AIObjectiveExtinguishFires.IsValidTarget(hull, Character))
{
AddTargets<AIObjectiveExtinguishFires, Hull>(Character, hull);
if (newOrder == null)
if (AddTargets<AIObjectiveExtinguishFires, Hull>(Character, hull) && newOrder == null)
{
var orderPrefab = Order.GetPrefab("reportfire");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
targetHull = hull;
}
}
foreach (Character c in Character.CharacterList)
@@ -556,13 +557,11 @@ namespace Barotrauma
if (c.CurrentHull != hull) { continue; }
if (AIObjectiveRescueAll.IsValidTarget(c, Character))
{
if (AddTargets<AIObjectiveRescueAll, Character>(c, Character))
if (AddTargets<AIObjectiveRescueAll, Character>(c, Character) && newOrder == null && !ObjectiveManager.HasActiveObjective<AIObjectiveRescue>())
{
if (newOrder == null)
{
var orderPrefab = Order.GetPrefab("requestfirstaid");
newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
}
var orderPrefab = Order.GetPrefab("requestfirstaid");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
targetHull = hull;
}
}
}
@@ -570,11 +569,11 @@ namespace Barotrauma
{
if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
{
AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap);
if (newOrder == null && !gap.IsRoomToRoom)
if (AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap) && newOrder == null && !gap.IsRoomToRoom)
{
var orderPrefab = Order.GetPrefab("reportbreach");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
targetHull = hull;
}
}
}
@@ -584,11 +583,11 @@ namespace Barotrauma
if (AIObjectiveRepairItems.IsValidTarget(item, Character))
{
if (item.Repairables.All(r => item.ConditionPercentage > r.ShowRepairUIThreshold)) { continue; }
AddTargets<AIObjectiveRepairItems, Item>(Character, item);
if (newOrder == null)
if (AddTargets<AIObjectiveRepairItems, Item>(Character, item) && newOrder == null && !ObjectiveManager.HasActiveObjective<AIObjectiveRepairItem>())
{
var orderPrefab = Order.GetPrefab("reportbrokendevices");
newOrder = new Order(orderPrefab, item.CurrentHull, item.Repairables?.FirstOrDefault(), orderGiver: Character);
newOrder = new Order(orderPrefab, hull, item.Repairables?.FirstOrDefault(), orderGiver: Character);
targetHull = hull;
}
}
}
@@ -598,9 +597,9 @@ namespace Barotrauma
{
if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
{
Character.Speak(newOrder.GetChatMessage("", Character.CurrentHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
Character.Speak(newOrder.GetChatMessage("", targetHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
#if SERVER
GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", Character.CurrentHull, null, Character));
GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", targetHull, null, Character));
#endif
}
}
@@ -191,7 +191,8 @@ namespace Barotrauma
{
diff.Y = 0.0f;
}
if (diff.LengthSquared() < 0.001f) { return -host.Steering; }
//if (diff.LengthSquared() < 0.001f) { return -host.Steering; }
if (diff == Vector2.Zero) { return Vector2.Zero; }
return Vector2.Normalize(diff) * weight;
}
@@ -71,7 +71,7 @@ namespace Barotrauma
foreach (FireSource fs in targetHull.FireSources)
{
bool inRange = fs.IsInDamageRange(character, MathHelper.Clamp(fs.DamageRange * 1.5f, extinguisher.Range * 0.5f, extinguisher.Range));
bool move = !inRange;
bool move = !inRange || !HumanAIController.VisibleHulls.Contains(fs.Hull);
if (inRange || useExtinquisherTimer > 0.0f)
{
useExtinquisherTimer += deltaTime;
@@ -79,7 +79,6 @@ namespace Barotrauma
{
useExtinquisherTimer = 0.0f;
}
character.AIController.SteeringManager.Reset();
character.CursorPosition = fs.Position;
if (extinguisher.Item.RequireAimToUse)
{
@@ -106,20 +105,19 @@ namespace Barotrauma
{
sightLimb = character.AnimController.GetLimb(LimbType.LeftHand);
}
if (!character.CanSeeTarget(fs, sightLimb))
if (character.CanSeeTarget(fs, sightLimb))
{
move = true;
}
else
{
move = false;
character.SetInput(extinguisher.Item.IsShootable ? InputType.Shoot : InputType.Use, false, true);
extinguisher.Use(deltaTime, character);
if (!targetHull.FireSources.Contains(fs))
{
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.Name, true), null, 0, "putoutfire", 10.0f);
{
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.RoomName, true), null, 0, "putoutfire", 10.0f);
}
}
else
{
move = true;
}
}
if (move)
{
@@ -128,6 +126,10 @@ namespace Barotrauma
onAbandon: () => Abandon = true,
onCompleted: () => RemoveSubObjective(ref gotoObjective));
}
else
{
character.AIController.SteeringManager.Reset();
}
break;
}
}
@@ -11,7 +11,7 @@ namespace Barotrauma
{
public override string DebugTag => "fight intruders";
protected override float IgnoreListClearInterval => 30;
public virtual bool IgnoreUnsafeHulls => true;
public override bool IgnoreUnsafeHulls => true;
public AIObjectiveFightIntruders(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
: base(character, objectiveManager, priorityModifier) { }
@@ -200,7 +200,7 @@ namespace Barotrauma
{
SteeringManager.SteeringSeek(character.GetRelativeSimPosition(Target), 10);
}
if (!insideSteering)
if (!insideSteering && character.CurrentHull == null)
{
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1);
}
@@ -293,7 +293,7 @@ namespace Barotrauma
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier)
{
IsLoop = true,
// Don't override auto pilot unless it's an order by a player
// Don't override unless it's an order by a player
Override = orderGiver == Character.Controlled || orderGiver.IsRemotePlayer
};
break;
@@ -302,7 +302,7 @@ namespace Barotrauma
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier)
{
IsLoop = true,
// Don't override auto control unless it's an order by a player
// Don't override unless it's an order by a player
Override = orderGiver == Character.Controlled || orderGiver.IsRemotePlayer
};
break;
@@ -24,6 +24,8 @@ namespace Barotrauma
public Entity OperateTarget => operateTarget;
public ItemComponent Component => component;
public ItemComponent GetTarget() => useController ? controller : component;
public Func<bool> completionCondition;
public override float GetPriority()
@@ -35,6 +37,7 @@ namespace Barotrauma
}
if (component.Item.CurrentHull == null) { return 0; }
if (component.Item.CurrentHull.FireSources.Count > 0) { return 0; }
if (IsOperatedByAnother(GetTarget())) { return 0; }
if (Character.CharacterList.Any(c => c.CurrentHull == component.Item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c))) { return 0; }
float devotion = MathHelper.Min(10, Priority);
float value = devotion + AIObjectiveManager.OrderPriority * PriorityModifier;
@@ -58,6 +61,45 @@ namespace Barotrauma
}
}
private bool IsOperatedByAnother(ItemComponent target)
{
foreach (var c in Character.CharacterList)
{
if (c == character) { continue; }
if (!HumanAIController.IsFriendly(c)) { continue; }
if (c.SelectedConstruction != target.Item) { continue; }
// If the other character is player, don't try to operate
if (c.IsRemotePlayer || Character.Controlled == c) { return true; }
if (c.AIController is HumanAIController humanAi)
{
// If the other character is ordered to operate the item, let him do it
if (humanAi.ObjectiveManager.IsCurrentOrder<AIObjectiveOperateItem>())
{
return true;
}
else
{
if (target is Steering)
{
// Steering is hard-coded -> cannot use the required skills collection defined in the xml
return character.GetSkillLevel("helm") <= c.GetSkillLevel("helm");
}
else
{
return target.DegreeOfSuccess(character) <= target.DegreeOfSuccess(c);
}
}
}
else
{
// Shouldn't go here, unless we allow non-humans to operate items
return false;
}
}
return false;
}
protected override void Act(float deltaTime)
{
if (character.LockHands)
@@ -65,24 +107,24 @@ namespace Barotrauma
Abandon = true;
return;
}
ItemComponent target = useController ? controller : component;
ItemComponent target = GetTarget();
if (useController && controller == null)
{
character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f);
Abandon = true;
return;
}
// Don't allow to operate an item that someone with a better skills already operates, unless this is an order
if (objectiveManager.CurrentOrder != this && IsOperatedByAnother(target))
{
// Don't abandon
return;
}
if (target.CanBeSelected)
{
if (character.CanInteractWith(target.Item, out _, checkLinked: false))
{
HumanAIController.FaceTarget(target.Item);
// Don't allow to operate an item that someone already operates, unless this objective is an order
if (objectiveManager.CurrentOrder != this && Character.CharacterList.Any(c => c.SelectedConstruction == target.Item && c != character && HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
{
// Don't abandon
return;
}
if (character.SelectedConstruction != target.Item)
{
target.Item.TryInteract(character, false, true);
@@ -764,12 +764,17 @@ namespace Barotrauma
.Where(p => p.AfflictionType == "huskinfection")
.Select(p => p as AfflictionPrefabHusk)
.FirstOrDefault(p => p.TargetSpecies.Any(t => t.Equals(AfflictionHusk.GetNonHuskedSpeciesName(speciesName, p), StringComparison.InvariantCultureIgnoreCase)));
string nonHuskedSpeciesName = string.Empty;
if (matchingAffliction == null)
{
DebugConsole.ThrowError("Cannot find a husk infection that matches this species! Please add the speciesnames as 'targets' in the husk affliction prefab definition!");
return;
// Crashes if we fail to create a ragdoll -> Let's just use some ragdoll so that the user sees the error msg.
nonHuskedSpeciesName = IsHumanoid ? HumanSpeciesName : "crawler";
}
else
{
nonHuskedSpeciesName = AfflictionHusk.GetNonHuskedSpeciesName(speciesName, matchingAffliction);
}
string nonHuskedSpeciesName = AfflictionHusk.GetNonHuskedSpeciesName(speciesName, matchingAffliction);
ragdollParams = IsHumanoid ? RagdollParams.GetDefaultRagdollParams<HumanRagdollParams>(nonHuskedSpeciesName) : RagdollParams.GetDefaultRagdollParams<FishRagdollParams>(nonHuskedSpeciesName) as RagdollParams;
if (info == null)
{
@@ -1912,7 +1917,7 @@ namespace Barotrauma
{
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
{
focusedCharacter = FindCharacterAtPosition(mouseSimPos);
focusedCharacter = CanInteract ? FindCharacterAtPosition(mouseSimPos) : null;
focusedItem = CanInteract ?
FindItemAtPosition(mouseSimPos, GameMain.Config.AimAssistAmount * (AnimController.InWater ? 1.5f : 1.0f)) : null;
findFocusedTimer = 0.05f;
@@ -1972,11 +1977,11 @@ namespace Barotrauma
{
DeselectCharacter();
}
else if (focusedCharacter != null && IsKeyHit(InputType.Grab) && FocusedCharacter.CanBeDragged)
else if (focusedCharacter != null && IsKeyHit(InputType.Grab) && FocusedCharacter.CanBeDragged && CanInteract)
{
SelectCharacter(focusedCharacter);
}
else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow && CanInteractWith(focusedCharacter, 160f, false))
else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow && CanInteract && CanInteractWith(focusedCharacter, 160f, false))
{
if (focusedCharacter == SelectedCharacter)
{
@@ -289,7 +289,7 @@ namespace Barotrauma
public static string GetNonHuskedSpeciesName(string huskedSpeciesName, AfflictionPrefabHusk prefab)
{
string nonTag = prefab.HuskedSpeciesName.Remove(AfflictionPrefabHusk.Tag);
return huskedSpeciesName.Remove(nonTag);
return huskedSpeciesName.ToLowerInvariant().Remove(nonTag);
}
}
}
@@ -41,7 +41,7 @@ namespace Barotrauma
{
public AfflictionPrefabHusk(XElement element, Type type = null) : base(element, type)
{
HuskedSpeciesName = element.GetAttributeString("huskedspeciesname", null);
HuskedSpeciesName = element.GetAttributeString("huskedspeciesname", null).ToLowerInvariant();
if (HuskedSpeciesName == null)
{
DebugConsole.NewMessage($"No 'huskedspeciesname' defined for the husk affliction ({Identifier}) in {element.ToString()}", Color.Orange);