diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs
index 16a7277ad..0006eb558 100644
--- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs
+++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs
@@ -436,7 +436,7 @@ namespace Barotrauma
InfoFrame.FindChild("showlog").Visible = GameMain.Server != null;
- campaignViewButton = new GUIButton(new Rectangle(0, 0, 130, 30), "Campaign view", Alignment.BottomRight, "", defaultModeContainer);
+ campaignViewButton = new GUIButton(new Rectangle(-80, 0, 120, 30), "Campaign view", Alignment.BottomRight, "", defaultModeContainer);
campaignViewButton.OnClicked = (btn, obj) => { ToggleCampaignView(true); return true; };
campaignViewButton.Visible = false;
diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems
index e28252c31..b1477e812 100644
--- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems
+++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems
@@ -741,6 +741,9 @@
PreserveNewest
+
+ Always
+
PreserveNewest
diff --git a/Barotrauma/BarotraumaShared/Data/clientpermissions.xml b/Barotrauma/BarotraumaShared/Data/clientpermissions.xml
new file mode 100644
index 000000000..ccc105b28
--- /dev/null
+++ b/Barotrauma/BarotraumaShared/Data/clientpermissions.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs
index 1ba1069c6..3e0f20f84 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs
@@ -64,7 +64,7 @@ namespace Barotrauma
protected override Vector2 DoSteeringSeek(Vector2 target, float speed = 1)
{
//find a new path if one hasn't been found yet or the target is different from the current target
- if (currentPath == null || Vector2.Distance(target, currentTarget)>1.0f || findPathTimer < -5.0f)
+ if (currentPath == null || Vector2.Distance(target, currentTarget) > 1.0f || findPathTimer < -1.0f)
{
if (findPathTimer > 0.0f) return Vector2.Zero;
@@ -73,21 +73,21 @@ namespace Barotrauma
if (character != null && character.Submarine == null)
{
var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false);
- if (targetHull!=null && targetHull.Submarine != null)
+ if (targetHull != null && targetHull.Submarine != null)
{
pos -= targetHull.SimPosition;
}
- }
+ }
currentPath = pathFinder.FindPath(pos, target);
- findPathTimer = Rand.Range(1.0f,1.2f);
+ findPathTimer = Rand.Range(1.0f, 1.2f);
return DiffToCurrentNode();
}
-
+
Vector2 diff = DiffToCurrentNode();
-
+
var collider = character.AnimController.Collider;
//if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
if (!character.AnimController.InWater &&
@@ -104,7 +104,7 @@ namespace Barotrauma
private Vector2 DiffToCurrentNode()
{
- if (currentPath == null || currentPath.Finished || currentPath.Unreachable) return Vector2.Zero;
+ if (currentPath == null || currentPath.Unreachable) return Vector2.Zero;
if (currentPath.Finished)
{
@@ -113,8 +113,8 @@ namespace Barotrauma
{
//todo: take multiple subs into account
pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition;
- }
- return currentTarget-pos2;
+ }
+ return currentTarget - pos2;
}
if (canOpenDoors && !character.LockHands) CheckDoorsInPath();
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs
index ee6381c50..0e527227e 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs
@@ -4,21 +4,13 @@ using System.Linq;
namespace Barotrauma
{
- class AIObjective
+ abstract class AIObjective
{
- protected List subObjectives;
-
+ protected readonly List subObjectives;
protected float priority;
-
- protected Character character;
-
+ protected readonly Character character;
protected string option;
- public virtual bool IsCompleted()
- {
- return false;
- }
-
public virtual bool CanBeCompleted
{
get { return true; }
@@ -27,15 +19,12 @@ namespace Barotrauma
public string Option
{
get { return option; }
- }
-
+ }
public AIObjective(Character character, string option)
{
subObjectives = new List();
-
this.character = character;
-
this.option = option;
#if DEBUG
@@ -60,8 +49,6 @@ namespace Barotrauma
Act(deltaTime);
}
- protected virtual void Act(float deltaTime) { }
-
public void AddSubObjective(AIObjective objective)
{
if (subObjectives.Any(o => o.IsDuplicate(objective))) return;
@@ -69,19 +56,20 @@ namespace Barotrauma
subObjectives.Add(objective);
}
- public virtual float GetPriority(Character character)
+ public AIObjective GetCurrentSubObjective()
{
- return 0.0f;
+ AIObjective currentSubObjective = this;
+ while (currentSubObjective.subObjectives.Count > 0)
+ {
+ currentSubObjective = subObjectives[0];
+ }
+ return currentSubObjective;
}
- public virtual bool IsDuplicate(AIObjective otherObjective)
- {
-#if DEBUG
- throw new NotImplementedException();
-#else
- return (this.GetType() == otherObjective.GetType());
-#endif
-
- }
+ protected abstract void Act(float deltaTime);
+
+ public abstract bool IsCompleted();
+ public abstract float GetPriority(AIObjectiveManager objectiveManager);
+ public abstract bool IsDuplicate(AIObjective otherObjective);
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveCombat.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveCombat.cs
index cbe66e791..cf84ae4f3 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveCombat.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveCombat.cs
@@ -33,7 +33,6 @@ namespace Barotrauma
}
coolDownTimer = CoolDown;
-
}
protected override void Act(float deltaTime)
@@ -41,17 +40,24 @@ namespace Barotrauma
coolDownTimer -= deltaTime;
var weapon = character.Inventory.FindItem("weapon");
-
- if (weapon==null)
+
+ if (weapon == null)
{
Escape(deltaTime);
}
else
{
+ //TODO: make sure the weapon is ready to use (projectiles/batteries loaded)
if (!character.SelectedItems.Contains(weapon))
{
- character.Inventory.TryPutItem(weapon, 3, false, character);
- weapon.Equip(character);
+ if (character.Inventory.TryPutItem(weapon, 3, false, character))
+ {
+ weapon.Equip(character);
+ }
+ else
+ {
+ return;
+ }
}
character.CursorPosition = enemy.Position;
character.SetInput(InputType.Aim, false, true);
@@ -99,8 +105,13 @@ namespace Barotrauma
return enemy.IsDead || coolDownTimer <= 0.0f;
}
- public override float GetPriority(Character character)
+ public override float GetPriority(AIObjectiveManager objectiveManager)
{
+ if (objectiveManager.CurrentOrder == this)
+ {
+ return AIObjectiveManager.OrderPriority;
+ }
+
//clamp the strength to the health of this character
//(it doesn't make a difference whether the enemy does 200 or 600 damage, it's one hit kill anyway)
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs
index bc92c927e..9dc4e26bc 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveContainItem.cs
@@ -19,15 +19,6 @@ namespace Barotrauma
{
this.itemName = itemName;
this.container = container;
-
- //check if the container has room for more items
- //canBeCompleted = false;
- //foreach (Item contained in container.inventory.Items)
- //{
- // if (contained != null) continue;
- // canBeCompleted = true;
- // break;
- //}
}
public override bool IsCompleted()
@@ -35,6 +26,16 @@ namespace Barotrauma
return isCompleted || container.Inventory.FindItem(itemName)!=null;
}
+ public override float GetPriority(AIObjectiveManager objectiveManager)
+ {
+ if (objectiveManager.CurrentOrder == this)
+ {
+ return AIObjectiveManager.OrderPriority;
+ }
+
+ return 1.0f;
+ }
+
protected override void Act(float deltaTime)
{
if (isCompleted) return;
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs
index 0b9928d66..132408dd3 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindDivingGear.cs
@@ -15,7 +15,7 @@ namespace Barotrauma
if (item == null) return false;
var containedItems = item.ContainedItems;
- var oxygenTank = Array.Find(containedItems, i => i.Name == "Oxygen Tank" && i.Condition > 0.0f);
+ var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank") && i.Condition > 0.0f);
return oxygenTank != null;
}
@@ -42,7 +42,7 @@ namespace Barotrauma
if (containedItems == null) return;
//check if there's an oxygen tank in the mask
- var oxygenTank = Array.Find(containedItems, i => i.Name == "Oxygen Tank");
+ var oxygenTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Oxygen Tank"));
if (oxygenTank != null)
{
@@ -66,15 +66,18 @@ namespace Barotrauma
if (subObjective != null)
{
subObjective.TryComplete(deltaTime);
-
- //isCompleted = subObjective.IsCompleted();
}
}
- public override float GetPriority(Character character)
+ public override float GetPriority(AIObjectiveManager objectiveManager)
{
if (character.AnimController.CurrentHull == null) return 100.0f;
+ if (objectiveManager.CurrentOrder == this)
+ {
+ return AIObjectiveManager.OrderPriority;
+ }
+
return 100.0f - character.Oxygen;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
index 56de5b8e5..391900d20 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
@@ -1,4 +1,5 @@
-using System;
+using Microsoft.Xna.Framework;
+using System;
using System.Collections.Generic;
using System.Linq;
@@ -27,39 +28,23 @@ namespace Barotrauma
unreachable = new List();
}
+ public override bool IsCompleted()
+ {
+ return false;
+ }
+
protected override void Act(float deltaTime)
{
-
var currentHull = character.AnimController.CurrentHull;
currenthullSafety = OverrideCurrentHullSafety == null ?
GetHullSafety(currentHull, character) : (float)OverrideCurrentHullSafety;
-
- if (currentHull != null)
+
+ if (NeedsDivingGear())
{
- if (NeedsDivingGear())
- {
- if (!FindDivingGear(deltaTime)) return;
- }
-
- if (currenthullSafety > MinSafety)
- {
- if (Math.Abs(currentHull.WorldPosition.X - character.WorldPosition.X) > 100.0f)
- {
- character.AIController.SteeringManager.SteeringSeek(currentHull.SimPosition, 0.5f);
- }
- else
- {
-
- character.AIController.SteeringManager.Reset();
- }
-
- character.AIController.SelectTarget(null);
-
- goToObjective = null;
- return;
- }
+ if (!FindDivingGear(deltaTime)) return;
}
+
if (searchHullTimer > 0.0f)
{
@@ -79,7 +64,7 @@ namespace Barotrauma
if (goToObjective != null)
{
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
- if (pathSteering!=null && pathSteering.CurrentPath!= null &&
+ if (pathSteering != null && pathSteering.CurrentPath != null &&
pathSteering.CurrentPath.Unreachable && !unreachable.Contains(goToObjective.Target))
{
unreachable.Add(goToObjective.Target as Hull);
@@ -92,7 +77,7 @@ namespace Barotrauma
private bool FindDivingGear(float deltaTime)
{
- if (divingGearObjective==null)
+ if (divingGearObjective == null)
{
divingGearObjective = new AIObjectiveFindDivingGear(character, false);
}
@@ -113,8 +98,9 @@ namespace Barotrauma
if (hull == character.AnimController.CurrentHull || unreachable.Contains(hull)) continue;
float hullValue = GetHullSafety(hull, character);
- hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X - hull.Position.X));
- hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y) * 2.0f);
+ //slight preference over hulls that are closer
+ hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X - hull.Position.X)) * 0.1f;
+ hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y)) * 0.2f;
if (bestHull == null || hullValue > bestValue)
{
@@ -144,13 +130,13 @@ namespace Barotrauma
return false;
}
- public override float GetPriority(Character character)
+ public override float GetPriority(AIObjectiveManager objectiveManager)
{
if (character.Oxygen < 80.0f)
{
return 150.0f - character.Oxygen;
}
-
+
if (character.AnimController.CurrentHull == null) return 5.0f;
currenthullSafety = GetHullSafety(character.AnimController.CurrentHull, character);
priority = 100.0f - currenthullSafety;
@@ -171,13 +157,12 @@ namespace Barotrauma
}
}
}
-
-
+
if (NeedsDivingGear())
{
if (divingGearObjective != null && !divingGearObjective.IsCompleted()) priority += 20.0f;
}
-
+
return priority;
}
@@ -185,11 +170,28 @@ namespace Barotrauma
{
if (hull == null) return 0.0f;
+ float safety = 100.0f;
+
float waterPercentage = (hull.WaterVolume / hull.Volume) * 100.0f;
+ if (hull.LethalPressure > 0.0f && character.PressureProtection <= 0.0f)
+ {
+ safety -= 100.0f;
+ }
+ else if (character.OxygenAvailable <= 0.0f)
+ {
+ safety -= waterPercentage;
+ }
+ else
+ {
+ safety -= waterPercentage * 0.1f;
+ }
+
+ if (hull.OxygenPercentage < 30.0f) safety -= (30.0f - hull.OxygenPercentage) * 5.0f;
+
+ if (safety <= 0.0f) return 0.0f;
+
float fireAmount = 0.0f;
-
var nearbyHulls = hull.GetConnectedHulls(3);
-
foreach (Hull hull2 in nearbyHulls)
{
foreach (FireSource fireSource in hull2.FireSources)
@@ -204,13 +206,9 @@ namespace Barotrauma
}
}
}
+ safety -= fireAmount;
- float safety = 100.0f - fireAmount;
-
- if (waterPercentage > 30.0f && character.OxygenAvailable <= 0.0f) safety -= waterPercentage;
- if (hull.OxygenPercentage < 30.0f) safety -= (30.0f - hull.OxygenPercentage) * 5.0f;
-
- return safety;
+ return MathHelper.Clamp(safety, 0.0f, 100.0f);
}
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs
index 356ed3590..f1e9bfd97 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs
@@ -7,7 +7,9 @@ namespace Barotrauma
{
class AIObjectiveFixLeak : AIObjective
{
- private Gap leak;
+ private readonly Gap leak;
+
+ private AIObjectiveGoTo gotoObjective;
public Gap Leak
{
@@ -20,15 +22,20 @@ namespace Barotrauma
this.leak = leak;
}
- public override float GetPriority(Character character)
+ public override bool IsCompleted()
+ {
+ return leak.Open <= 0.0f || leak.Removed;
+ }
+
+ public override float GetPriority(AIObjectiveManager objectiveManager)
{
if (leak.Open == 0.0f) return 0.0f;
float leakSize = (leak.IsHorizontal ? leak.Rect.Height : leak.Rect.Width) * Math.Max(leak.Open, 0.1f);
float dist = Vector2.DistanceSquared(character.SimPosition, leak.SimPosition);
- dist = Math.Max(dist/100.0f, 1.0f);
- return Math.Min(leakSize/dist, 40.0f);
+ dist = Math.Max(dist / 100.0f, 1.0f);
+ return Math.Min(leakSize / dist, 40.0f);
}
public override bool IsDuplicate(AIObjective otherObjective)
@@ -44,7 +51,7 @@ namespace Barotrauma
if (weldingTool == null)
{
- subObjectives.Add(new AIObjectiveGetItem(character, "Welding Tool", true));
+ AddSubObjective(new AIObjectiveGetItem(character, "Welding Tool", true));
return;
}
else
@@ -52,25 +59,31 @@ namespace Barotrauma
var containedItems = weldingTool.ContainedItems;
if (containedItems == null) return;
- var fuelTank = Array.Find(containedItems, i => i.Name == "Welding Fuel Tank" && i.Condition > 0.0f);
+ var fuelTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Welding Fuel Tank") && i.Condition > 0.0f);
if (fuelTank == null)
{
AddSubObjective(new AIObjectiveContainItem(character, "Welding Fuel Tank", weldingTool.GetComponent()));
+ return;
}
}
var repairTool = weldingTool.GetComponent();
if (repairTool == null) return;
- if (Vector2.Distance(character.WorldPosition, leak.WorldPosition) > 300.0f)
+ Vector2 standPosition = GetStandPosition();
+
+ if (Vector2.DistanceSquared(character.WorldPosition, leak.WorldPosition) > 100.0f * 100.0f)
{
- AddSubObjective(new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character));
+ var gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(standPosition), character);
+ if (!gotoObjective.IsCompleted())
+ {
+ AddSubObjective(gotoObjective);
+ return;
+ }
}
- else
- {
- AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", leak));
- }
+
+ AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", true, leak));
}
private Vector2 GetStandPosition()
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs
index f29971f03..2414a726c 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs
@@ -7,38 +7,80 @@ namespace Barotrauma
{
class AIObjectiveFixLeaks : AIObjective
{
- const float UpdateGapListInterval = 10.0f;
+ const float UpdateGapListInterval = 5.0f;
- private float updateGapListTimer;
+ private double lastGapUpdate;
private AIObjectiveIdle idleObjective;
+ private AIObjectiveFindDivingGear findDivingGear;
+
private List objectiveList;
public AIObjectiveFixLeaks(Character character)
: base (character, "")
{
- objectiveList = new List();
}
public override bool IsCompleted()
{
- return false;
+ if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
+ {
+ UpdateGapList();
+ lastGapUpdate = Timing.TotalTime;
+ }
+
+ return objectiveList.Count == 0;
+ }
+
+ public override float GetPriority(AIObjectiveManager objectiveManager)
+ {
+ if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
+ {
+ UpdateGapList();
+ lastGapUpdate = Timing.TotalTime;
+ }
+
+ float priority = 0.0f;
+ foreach (AIObjectiveFixLeak fixObjective in objectiveList)
+ {
+ //gaps from outside to inside significantly increase the priority
+ if (!fixObjective.Leak.IsRoomToRoom)
+ {
+ priority = Math.Max(priority + fixObjective.Leak.Open * 100.0f, 50.0f);
+ }
+ else
+ {
+ priority += fixObjective.Leak.Open * 10.0f;
+ }
+
+ if (priority >= 100.0f) break;
+ }
+
+ return Math.Min(priority, 100.0f);
}
protected override void Act(float deltaTime)
{
- updateGapListTimer -= deltaTime;
-
- if (updateGapListTimer<=0.0f)
+ if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
{
UpdateGapList();
-
- updateGapListTimer = UpdateGapListInterval;
+ lastGapUpdate = Timing.TotalTime;
}
if (objectiveList.Any())
{
+ if (!objectiveList[objectiveList.Count - 1].Leak.IsRoomToRoom)
+ {
+ if (findDivingGear == null) findDivingGear = new AIObjectiveFindDivingGear(character, true);
+
+ if (!findDivingGear.IsCompleted() && findDivingGear.CanBeCompleted)
+ {
+ findDivingGear.TryComplete(deltaTime);
+ return;
+ }
+ }
+
objectiveList[objectiveList.Count - 1].TryComplete(deltaTime);
if (!objectiveList[objectiveList.Count - 1].CanBeCompleted ||
@@ -56,6 +98,7 @@ namespace Barotrauma
private void UpdateGapList()
{
+ if (objectiveList == null) objectiveList = new List();
objectiveList.Clear();
foreach (Gap gap in Gap.GapList)
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs
index 07aec2f29..05c80fa69 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs
@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
+using System;
namespace Barotrauma
{
@@ -26,6 +27,16 @@ namespace Barotrauma
get { return canBeCompleted; }
}
+ public override float GetPriority(AIObjectiveManager objectiveManager)
+ {
+ if (objectiveManager.CurrentOrder == this)
+ {
+ return AIObjectiveManager.OrderPriority;
+ }
+
+ return 1.0f;
+ }
+
public AIObjectiveGetItem(Character character, Item targetItem, bool equip = false)
: base(character, "")
{
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs
index 3a9b2e037..cf566bd8a 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs
@@ -18,6 +18,16 @@ namespace Barotrauma
private bool getDivingGearIfNeeded;
+ public override float GetPriority(AIObjectiveManager objectiveManager)
+ {
+ if (objectiveManager.CurrentOrder == this)
+ {
+ return AIObjectiveManager.OrderPriority;
+ }
+
+ return 1.0f;
+ }
+
public override bool CanBeCompleted
{
get
@@ -93,7 +103,7 @@ namespace Barotrauma
}
}
- if (Vector2.Distance(currTargetPos, character.SimPosition) < 1.0f)
+ if (Vector2.DistanceSquared(currTargetPos, character.SimPosition) < 0.5f * 0.5f)
{
character.AIController.SteeringManager.Reset();
character.AnimController.TargetDir = currTargetPos.X > character.SimPosition.X ? Direction.Right : Direction.Left;
@@ -104,7 +114,7 @@ namespace Barotrauma
var indoorsSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
- if (indoorsSteering.CurrentPath==null || indoorsSteering.CurrentPath.Unreachable)
+ if (indoorsSteering.CurrentPath == null || indoorsSteering.CurrentPath.Unreachable)
{
indoorsSteering.SteeringWander();
}
@@ -130,7 +140,7 @@ namespace Barotrauma
if (item.IsInsideTrigger(character.WorldPosition)) completed = true;
}
- completed = completed || Vector2.Distance(target != null ? target.SimPosition : targetPos, character.SimPosition) < allowedDistance;
+ completed = completed || Vector2.DistanceSquared(target != null ? target.SimPosition : targetPos, character.SimPosition) < allowedDistance * allowedDistance;
if (completed) character.AIController.SteeringManager.Reset();
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs
index 59b5b6f6a..6d0c6df9f 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs
@@ -9,15 +9,21 @@ namespace Barotrauma
{
const float WallAvoidDistance = 150.0f;
- AITarget currentTarget;
+ private AITarget currentTarget;
private float newTargetTimer;
+ private AIObjectiveFindSafety findSafety;
+
public AIObjectiveIdle(Character character) : base(character, "")
{
-
}
- public override float GetPriority(Character character)
+ public override bool IsCompleted()
+ {
+ return false;
+ }
+
+ public override float GetPriority(AIObjectiveManager objectiveManager)
{
return 1.0f;
}
@@ -31,6 +37,14 @@ namespace Barotrauma
{
return;
}
+
+ if (character.AnimController.InWater)
+ {
+ //attempt to find a safer place if in water
+ if (findSafety == null) findSafety = new AIObjectiveFindSafety(character);
+ findSafety.TryComplete(deltaTime);
+ return;
+ }
if (newTargetTimer <= 0.0f)
{
@@ -92,17 +106,10 @@ namespace Barotrauma
return;
}
}
-
- if (character.AnimController.InWater)
- {
- character.AIController.SteeringManager.SteeringManual(deltaTime, new Vector2(0.0f, 0.5f));
- }
- else
- {
- character.AIController.SteeringManager.SteeringWander();
- //reset vertical steering to prevent dropping down from platforms etc
- character.AIController.SteeringManager.ResetY();
- }
+
+ character.AIController.SteeringManager.SteeringWander();
+ //reset vertical steering to prevent dropping down from platforms etc
+ character.AIController.SteeringManager.ResetY();
return;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
index 8482e3867..468434e8c 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveManager.cs
@@ -11,15 +11,17 @@ namespace Barotrauma
private Character character;
- private AIObjective currentObjective;
+ private AIObjective currentOrder;
+ public AIObjective CurrentOrder
+ {
+ get { return currentOrder; }
+ }
+
public AIObjective CurrentObjective
{
- get
- {
- if (currentObjective != null) return currentObjective;
- return objectives.Any() ? objectives[0] : null;
- }
+ get;
+ private set;
}
public AIObjectiveManager(Character character)
@@ -47,8 +49,13 @@ namespace Barotrauma
public float GetCurrentPriority(Character character)
{
- if (currentObjective != null) return OrderPriority;
- return (CurrentObjective == null) ? 0.0f : CurrentObjective.GetPriority(character);
+ if (CurrentOrder != null &&
+ (objectives.Count == 0 || currentOrder.GetPriority(this) > objectives[0].GetPriority(this)))
+ {
+ return CurrentOrder.GetPriority(this);
+ }
+
+ return objectives.Count == 0 ? 0.0f : objectives[0].GetPriority(this);
}
public void UpdateObjectives()
@@ -59,43 +66,46 @@ namespace Barotrauma
objectives = objectives.FindAll(o => !o.IsCompleted() && o.CanBeCompleted);
//sort objectives according to priority
- objectives.Sort((x, y) => y.GetPriority(character).CompareTo(x.GetPriority(character)));
+ objectives.Sort((x, y) => y.GetPriority(this).CompareTo(x.GetPriority(this)));
}
public void DoCurrentObjective(float deltaTime)
{
- if (currentObjective != null && (!objectives.Any() || objectives[0].GetPriority(character) < OrderPriority))
+ if (currentOrder != null && (!objectives.Any() || objectives[0].GetPriority(this) < currentOrder.GetPriority(this)))
{
- currentObjective.TryComplete(deltaTime);
+ CurrentObjective = currentOrder;
+ currentOrder.TryComplete(deltaTime);
return;
}
if (!objectives.Any()) return;
objectives[0].TryComplete(deltaTime);
+
+ CurrentObjective = objectives[0];
}
public void SetOrder(Order order, string option)
{
if (order == null) return;
- currentObjective = null;
+ currentOrder = null;
switch (order.Name.ToLowerInvariant())
{
case "follow":
- currentObjective = new AIObjectiveGoTo(Character.Controlled, character, true);
+ currentOrder = new AIObjectiveGoTo(Character.Controlled, character, true);
break;
case "wait":
- currentObjective = new AIObjectiveGoTo(character, character, true);
+ currentOrder = new AIObjectiveGoTo(character, character, true);
break;
case "fixleaks":
case "fix leaks":
- currentObjective = new AIObjectiveFixLeaks(character);
+ currentOrder = new AIObjectiveFixLeaks(character);
break;
default:
if (order.TargetItem == null) return;
- currentObjective = new AIObjectiveOperateItem(order.TargetItem, character, option, null, order.UseController);
+ currentOrder = new AIObjectiveOperateItem(order.TargetItem, character, option, false, null, order.UseController);
break;
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
index 9788393a3..061442e73 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
@@ -1,5 +1,6 @@
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
+using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
@@ -14,6 +15,8 @@ namespace Barotrauma
private bool canBeCompleted;
+ private bool requireEquip;
+
public override bool CanBeCompleted
{
get
@@ -27,11 +30,21 @@ namespace Barotrauma
get { return operateTarget; }
}
- public AIObjectiveOperateItem(ItemComponent item, Character character, string option, Entity operateTarget = null, bool useController = false)
- :base (character, option)
+ public override float GetPriority(AIObjectiveManager objectiveManager)
+ {
+ if (objectiveManager.CurrentOrder == this)
+ {
+ return AIObjectiveManager.OrderPriority;
+ }
+
+ return 1.0f;
+ }
+
+ public AIObjectiveOperateItem(ItemComponent item, Character character, string option, bool requireEquip, Entity operateTarget = null, bool useController = false)
+ : base (character, option)
{
this.component = item;
-
+ this.requireEquip = requireEquip;
this.operateTarget = operateTarget;
if (useController)
@@ -72,6 +85,43 @@ namespace Barotrauma
}
else
{
+ if (requireEquip && !character.HasEquippedItem(component.Item))
+ {
+ //the item has to be equipped before using it if it's holdable
+ var holdable = component.Item.GetComponent();
+ if (holdable == null)
+ {
+ DebugConsole.ThrowError("AIObjectiveOperateItem failed - equipping item " + component.Item + " is required but the item has no Holdable component");
+ return;
+ }
+
+ for (int i = 0; i < CharacterInventory.limbSlots.Length; i++)
+ {
+ if (CharacterInventory.limbSlots[i] == InvSlotType.Any ||
+ !holdable.AllowedSlots.Any(s => s.HasFlag(CharacterInventory.limbSlots[i])))
+ {
+ continue;
+ }
+
+ //equip slot already taken
+ if (character.Inventory.Items[i] != null)
+ {
+ //try to put the item in an Any slot, and drop it if that fails
+ if (!character.Inventory.Items[i].AllowedSlots.Contains(InvSlotType.Any) ||
+ !character.Inventory.TryPutItem(character.Inventory.Items[i], character, new List() { InvSlotType.Any }))
+ {
+ character.Inventory.Items[i].Drop();
+ }
+ }
+ if (character.Inventory.TryPutItem(component.Item, i, true, character))
+ {
+ component.Item.Equip(character);
+ break;
+ }
+ }
+ return;
+ }
+
if (component.AIOperate(deltaTime, character, this)) isCompleted = true;
}
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs
index 84f291d48..60391493f 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescue.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
namespace Barotrauma
{
- class AIObjectiveRescue : AIObjective
+ /*class AIObjectiveRescue : AIObjective
{
private readonly Character targetCharacter;
@@ -30,5 +30,5 @@ namespace Barotrauma
return targetCharacter.IsDead ? 1000.0f / distance : 10000.0f / distance;
}
- }
+ }*/
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs
index adeb631b9..784b76859 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRescueAll.cs
@@ -3,7 +3,7 @@ using System.Linq;
namespace Barotrauma
{
- class AIObjectiveRescueAll : AIObjective
+ /*class AIObjectiveRescueAll : AIObjective
{
private List rescueTargets;
@@ -44,5 +44,5 @@ namespace Barotrauma
AddSubObjective(new AIObjectiveRescue(character, target));
}
}
- }
+ }*/
}
diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs
index 4424e713a..da7694ae1 100644
--- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs
+++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs
@@ -197,7 +197,7 @@ namespace Barotrauma
{
get { return !IsUnconscious && Stun <= 0.0f && !isDead; }
}
-
+
public bool CanInteract
{
get { return AllowInput && IsHumanoid && !LockHands; }
@@ -303,11 +303,11 @@ namespace Barotrauma
get { return needsAir; }
set { needsAir = value; }
}
-
+
public float Oxygen
{
get { return oxygen; }
- set
+ set
{
if (!MathUtils.IsValid(value)) return;
oxygen = MathHelper.Clamp(value, -100.0f, 100.0f);
@@ -331,7 +331,7 @@ namespace Barotrauma
{
if (GameMain.Client != null) return;
- SetStun(value);
+ SetStun(value);
}
}
@@ -358,7 +358,7 @@ namespace Barotrauma
}*/
}
}
-
+
public float MaxHealth
{
get { return maxHealth; }
@@ -367,12 +367,12 @@ namespace Barotrauma
public float Bleeding
{
get { return bleeding; }
- set
+ set
{
if (!MathUtils.IsValid(value)) return;
if (GameMain.Client != null) return;
- float newBleeding = MathHelper.Clamp(value, 0.0f, 5.0f);
+ float newBleeding = MathHelper.Clamp(value, 0.0f, 5.0f);
//if (newBleeding == bleeding) return;
bleeding = newBleeding;
@@ -381,18 +381,18 @@ namespace Barotrauma
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });*/
}
}
-
+
public HuskInfection huskInfection;
public float HuskInfectionState
{
- get
- {
- return huskInfection == null ? 0.0f : huskInfection.IncubationTimer;
+ get
+ {
+ return huskInfection == null ? 0.0f : huskInfection.IncubationTimer;
}
set
{
if (ConfigPath != humanConfigFile) return;
-
+
if (value <= 0.0f)
{
if (huskInfection != null)
@@ -448,7 +448,7 @@ namespace Barotrauma
get;
set;
}
-
+
public Item[] SelectedItems
{
get { return selectedItems; }
@@ -465,6 +465,12 @@ namespace Barotrauma
get { return focusedItem; }
}
+ public Item PickingItem
+ {
+ get;
+ set;
+ }
+
public virtual AIController AIController
{
get { return null; }
diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Pickable.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Pickable.cs
index 69e06f783..482aee51f 100644
--- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Pickable.cs
+++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Pickable.cs
@@ -13,7 +13,6 @@ namespace Barotrauma.Items.Components
private float pickTimer;
-
public List AllowedSlots
{
get { return allowedSlots; }
@@ -55,13 +54,15 @@ namespace Barotrauma.Items.Components
public override bool Pick(Character picker)
{
//return if someone is already trying to pick the item
- if (pickTimer>0.0f) return false;
+ if (pickTimer > 0.0f) return false;
if (picker == null || picker.Inventory == null) return false;
- if (PickingTime>0.0f)
+ if (PickingTime > 0.0f)
{
- CoroutineManager.StartCoroutine(WaitForPick(picker, PickingTime));
-
+ if (picker.PickingItem == null)
+ {
+ CoroutineManager.StartCoroutine(WaitForPick(picker, PickingTime));
+ }
return false;
}
else
@@ -104,6 +105,8 @@ namespace Barotrauma.Items.Components
private IEnumerable