This commit is contained in:
juanjp600
2017-12-21 20:31:24 -03:00
23 changed files with 347 additions and 190 deletions
@@ -436,7 +436,7 @@ namespace Barotrauma
InfoFrame.FindChild("showlog").Visible = GameMain.Server != null; 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.OnClicked = (btn, obj) => { ToggleCampaignView(true); return true; };
campaignViewButton.Visible = false; campaignViewButton.Visible = false;
@@ -741,6 +741,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\waterbump.png"> <Content Include="$(MSBuildThisFileDirectory)Content\waterbump.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="$(MSBuildThisFileDirectory)Data\clientpermissions.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Data\ContentPackages\Vanilla 0.7.xml"> <Content Include="$(MSBuildThisFileDirectory)Data\ContentPackages\Vanilla 0.7.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<ClientPermissions>
</ClientPermissions>
@@ -64,7 +64,7 @@ namespace Barotrauma
protected override Vector2 DoSteeringSeek(Vector2 target, float speed = 1) 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 //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; if (findPathTimer > 0.0f) return Vector2.Zero;
@@ -73,7 +73,7 @@ namespace Barotrauma
if (character != null && character.Submarine == null) if (character != null && character.Submarine == null)
{ {
var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false); 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; pos -= targetHull.SimPosition;
} }
@@ -81,7 +81,7 @@ namespace Barotrauma
currentPath = pathFinder.FindPath(pos, target); currentPath = pathFinder.FindPath(pos, target);
findPathTimer = Rand.Range(1.0f,1.2f); findPathTimer = Rand.Range(1.0f, 1.2f);
return DiffToCurrentNode(); return DiffToCurrentNode();
} }
@@ -104,7 +104,7 @@ namespace Barotrauma
private Vector2 DiffToCurrentNode() private Vector2 DiffToCurrentNode()
{ {
if (currentPath == null || currentPath.Finished || currentPath.Unreachable) return Vector2.Zero; if (currentPath == null || currentPath.Unreachable) return Vector2.Zero;
if (currentPath.Finished) if (currentPath.Finished)
{ {
@@ -114,7 +114,7 @@ namespace Barotrauma
//todo: take multiple subs into account //todo: take multiple subs into account
pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition; pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition;
} }
return currentTarget-pos2; return currentTarget - pos2;
} }
if (canOpenDoors && !character.LockHands) CheckDoorsInPath(); if (canOpenDoors && !character.LockHands) CheckDoorsInPath();
@@ -4,21 +4,13 @@ using System.Linq;
namespace Barotrauma namespace Barotrauma
{ {
class AIObjective abstract class AIObjective
{ {
protected List<AIObjective> subObjectives; protected readonly List<AIObjective> subObjectives;
protected float priority; protected float priority;
protected readonly Character character;
protected Character character;
protected string option; protected string option;
public virtual bool IsCompleted()
{
return false;
}
public virtual bool CanBeCompleted public virtual bool CanBeCompleted
{ {
get { return true; } get { return true; }
@@ -29,13 +21,10 @@ namespace Barotrauma
get { return option; } get { return option; }
} }
public AIObjective(Character character, string option) public AIObjective(Character character, string option)
{ {
subObjectives = new List<AIObjective>(); subObjectives = new List<AIObjective>();
this.character = character; this.character = character;
this.option = option; this.option = option;
#if DEBUG #if DEBUG
@@ -60,8 +49,6 @@ namespace Barotrauma
Act(deltaTime); Act(deltaTime);
} }
protected virtual void Act(float deltaTime) { }
public void AddSubObjective(AIObjective objective) public void AddSubObjective(AIObjective objective)
{ {
if (subObjectives.Any(o => o.IsDuplicate(objective))) return; if (subObjectives.Any(o => o.IsDuplicate(objective))) return;
@@ -69,19 +56,20 @@ namespace Barotrauma
subObjectives.Add(objective); 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) protected abstract void Act(float deltaTime);
{
#if DEBUG
throw new NotImplementedException();
#else
return (this.GetType() == otherObjective.GetType());
#endif
} public abstract bool IsCompleted();
public abstract float GetPriority(AIObjectiveManager objectiveManager);
public abstract bool IsDuplicate(AIObjective otherObjective);
} }
} }
@@ -33,7 +33,6 @@ namespace Barotrauma
} }
coolDownTimer = CoolDown; coolDownTimer = CoolDown;
} }
protected override void Act(float deltaTime) protected override void Act(float deltaTime)
@@ -42,16 +41,23 @@ namespace Barotrauma
var weapon = character.Inventory.FindItem("weapon"); var weapon = character.Inventory.FindItem("weapon");
if (weapon==null) if (weapon == null)
{ {
Escape(deltaTime); Escape(deltaTime);
} }
else else
{ {
//TODO: make sure the weapon is ready to use (projectiles/batteries loaded)
if (!character.SelectedItems.Contains(weapon)) if (!character.SelectedItems.Contains(weapon))
{ {
character.Inventory.TryPutItem(weapon, 3, false, character); if (character.Inventory.TryPutItem(weapon, 3, false, character))
weapon.Equip(character); {
weapon.Equip(character);
}
else
{
return;
}
} }
character.CursorPosition = enemy.Position; character.CursorPosition = enemy.Position;
character.SetInput(InputType.Aim, false, true); character.SetInput(InputType.Aim, false, true);
@@ -99,8 +105,13 @@ namespace Barotrauma
return enemy.IsDead || coolDownTimer <= 0.0f; 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 //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) //(it doesn't make a difference whether the enemy does 200 or 600 damage, it's one hit kill anyway)
@@ -19,15 +19,6 @@ namespace Barotrauma
{ {
this.itemName = itemName; this.itemName = itemName;
this.container = container; 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() public override bool IsCompleted()
@@ -35,6 +26,16 @@ namespace Barotrauma
return isCompleted || container.Inventory.FindItem(itemName)!=null; 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) protected override void Act(float deltaTime)
{ {
if (isCompleted) return; if (isCompleted) return;
@@ -15,7 +15,7 @@ namespace Barotrauma
if (item == null) return false; if (item == null) return false;
var containedItems = item.ContainedItems; 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; return oxygenTank != null;
} }
@@ -42,7 +42,7 @@ namespace Barotrauma
if (containedItems == null) return; if (containedItems == null) return;
//check if there's an oxygen tank in the mask //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) if (oxygenTank != null)
{ {
@@ -66,15 +66,18 @@ namespace Barotrauma
if (subObjective != null) if (subObjective != null)
{ {
subObjective.TryComplete(deltaTime); 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 (character.AnimController.CurrentHull == null) return 100.0f;
if (objectiveManager.CurrentOrder == this)
{
return AIObjectiveManager.OrderPriority;
}
return 100.0f - character.Oxygen; return 100.0f - character.Oxygen;
} }
@@ -1,4 +1,5 @@
using System; using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -27,40 +28,24 @@ namespace Barotrauma
unreachable = new List<Hull>(); unreachable = new List<Hull>();
} }
public override bool IsCompleted()
{
return false;
}
protected override void Act(float deltaTime) protected override void Act(float deltaTime)
{ {
var currentHull = character.AnimController.CurrentHull; var currentHull = character.AnimController.CurrentHull;
currenthullSafety = OverrideCurrentHullSafety == null ? currenthullSafety = OverrideCurrentHullSafety == null ?
GetHullSafety(currentHull, character) : (float)OverrideCurrentHullSafety; GetHullSafety(currentHull, character) : (float)OverrideCurrentHullSafety;
if (currentHull != null) if (NeedsDivingGear())
{ {
if (NeedsDivingGear()) if (!FindDivingGear(deltaTime)) return;
{
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 (searchHullTimer > 0.0f) if (searchHullTimer > 0.0f)
{ {
searchHullTimer -= deltaTime; searchHullTimer -= deltaTime;
@@ -79,7 +64,7 @@ namespace Barotrauma
if (goToObjective != null) if (goToObjective != null)
{ {
var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager; 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)) pathSteering.CurrentPath.Unreachable && !unreachable.Contains(goToObjective.Target))
{ {
unreachable.Add(goToObjective.Target as Hull); unreachable.Add(goToObjective.Target as Hull);
@@ -92,7 +77,7 @@ namespace Barotrauma
private bool FindDivingGear(float deltaTime) private bool FindDivingGear(float deltaTime)
{ {
if (divingGearObjective==null) if (divingGearObjective == null)
{ {
divingGearObjective = new AIObjectiveFindDivingGear(character, false); divingGearObjective = new AIObjectiveFindDivingGear(character, false);
} }
@@ -113,8 +98,9 @@ namespace Barotrauma
if (hull == character.AnimController.CurrentHull || unreachable.Contains(hull)) continue; if (hull == character.AnimController.CurrentHull || unreachable.Contains(hull)) continue;
float hullValue = GetHullSafety(hull, character); float hullValue = GetHullSafety(hull, character);
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.X - hull.Position.X)); //slight preference over hulls that are closer
hullValue -= (float)Math.Sqrt(Math.Abs(character.Position.Y - hull.Position.Y) * 2.0f); 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) if (bestHull == null || hullValue > bestValue)
{ {
@@ -144,7 +130,7 @@ namespace Barotrauma
return false; return false;
} }
public override float GetPriority(Character character) public override float GetPriority(AIObjectiveManager objectiveManager)
{ {
if (character.Oxygen < 80.0f) if (character.Oxygen < 80.0f)
{ {
@@ -172,7 +158,6 @@ namespace Barotrauma
} }
} }
if (NeedsDivingGear()) if (NeedsDivingGear())
{ {
if (divingGearObjective != null && !divingGearObjective.IsCompleted()) priority += 20.0f; if (divingGearObjective != null && !divingGearObjective.IsCompleted()) priority += 20.0f;
@@ -185,11 +170,28 @@ namespace Barotrauma
{ {
if (hull == null) return 0.0f; if (hull == null) return 0.0f;
float safety = 100.0f;
float waterPercentage = (hull.WaterVolume / hull.Volume) * 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; float fireAmount = 0.0f;
var nearbyHulls = hull.GetConnectedHulls(3); var nearbyHulls = hull.GetConnectedHulls(3);
foreach (Hull hull2 in nearbyHulls) foreach (Hull hull2 in nearbyHulls)
{ {
foreach (FireSource fireSource in hull2.FireSources) foreach (FireSource fireSource in hull2.FireSources)
@@ -204,13 +206,9 @@ namespace Barotrauma
} }
} }
} }
safety -= fireAmount;
float safety = 100.0f - fireAmount; return MathHelper.Clamp(safety, 0.0f, 100.0f);
if (waterPercentage > 30.0f && character.OxygenAvailable <= 0.0f) safety -= waterPercentage;
if (hull.OxygenPercentage < 30.0f) safety -= (30.0f - hull.OxygenPercentage) * 5.0f;
return safety;
} }
} }
} }
@@ -7,7 +7,9 @@ namespace Barotrauma
{ {
class AIObjectiveFixLeak : AIObjective class AIObjectiveFixLeak : AIObjective
{ {
private Gap leak; private readonly Gap leak;
private AIObjectiveGoTo gotoObjective;
public Gap Leak public Gap Leak
{ {
@@ -20,15 +22,20 @@ namespace Barotrauma
this.leak = leak; 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; 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 leakSize = (leak.IsHorizontal ? leak.Rect.Height : leak.Rect.Width) * Math.Max(leak.Open, 0.1f);
float dist = Vector2.DistanceSquared(character.SimPosition, leak.SimPosition); float dist = Vector2.DistanceSquared(character.SimPosition, leak.SimPosition);
dist = Math.Max(dist/100.0f, 1.0f); dist = Math.Max(dist / 100.0f, 1.0f);
return Math.Min(leakSize/dist, 40.0f); return Math.Min(leakSize / dist, 40.0f);
} }
public override bool IsDuplicate(AIObjective otherObjective) public override bool IsDuplicate(AIObjective otherObjective)
@@ -44,7 +51,7 @@ namespace Barotrauma
if (weldingTool == null) if (weldingTool == null)
{ {
subObjectives.Add(new AIObjectiveGetItem(character, "Welding Tool", true)); AddSubObjective(new AIObjectiveGetItem(character, "Welding Tool", true));
return; return;
} }
else else
@@ -52,25 +59,31 @@ namespace Barotrauma
var containedItems = weldingTool.ContainedItems; var containedItems = weldingTool.ContainedItems;
if (containedItems == null) return; 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) if (fuelTank == null)
{ {
AddSubObjective(new AIObjectiveContainItem(character, "Welding Fuel Tank", weldingTool.GetComponent<ItemContainer>())); AddSubObjective(new AIObjectiveContainItem(character, "Welding Fuel Tank", weldingTool.GetComponent<ItemContainer>()));
return;
} }
} }
var repairTool = weldingTool.GetComponent<RepairTool>(); var repairTool = weldingTool.GetComponent<RepairTool>();
if (repairTool == null) return; 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())
else {
{ AddSubObjective(gotoObjective);
AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", leak)); return;
}
} }
AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", true, leak));
} }
private Vector2 GetStandPosition() private Vector2 GetStandPosition()
@@ -7,38 +7,80 @@ namespace Barotrauma
{ {
class AIObjectiveFixLeaks : AIObjective class AIObjectiveFixLeaks : AIObjective
{ {
const float UpdateGapListInterval = 10.0f; const float UpdateGapListInterval = 5.0f;
private float updateGapListTimer; private double lastGapUpdate;
private AIObjectiveIdle idleObjective; private AIObjectiveIdle idleObjective;
private AIObjectiveFindDivingGear findDivingGear;
private List<AIObjectiveFixLeak> objectiveList; private List<AIObjectiveFixLeak> objectiveList;
public AIObjectiveFixLeaks(Character character) public AIObjectiveFixLeaks(Character character)
: base (character, "") : base (character, "")
{ {
objectiveList = new List<AIObjectiveFixLeak>();
} }
public override bool IsCompleted() 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) protected override void Act(float deltaTime)
{ {
updateGapListTimer -= deltaTime; if (Timing.TotalTime > lastGapUpdate + UpdateGapListInterval || objectiveList == null)
if (updateGapListTimer<=0.0f)
{ {
UpdateGapList(); UpdateGapList();
lastGapUpdate = Timing.TotalTime;
updateGapListTimer = UpdateGapListInterval;
} }
if (objectiveList.Any()) 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); objectiveList[objectiveList.Count - 1].TryComplete(deltaTime);
if (!objectiveList[objectiveList.Count - 1].CanBeCompleted || if (!objectiveList[objectiveList.Count - 1].CanBeCompleted ||
@@ -56,6 +98,7 @@ namespace Barotrauma
private void UpdateGapList() private void UpdateGapList()
{ {
if (objectiveList == null) objectiveList = new List<AIObjectiveFixLeak>();
objectiveList.Clear(); objectiveList.Clear();
foreach (Gap gap in Gap.GapList) foreach (Gap gap in Gap.GapList)
@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System;
namespace Barotrauma namespace Barotrauma
{ {
@@ -26,6 +27,16 @@ namespace Barotrauma
get { return canBeCompleted; } 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) public AIObjectiveGetItem(Character character, Item targetItem, bool equip = false)
: base(character, "") : base(character, "")
{ {
@@ -18,6 +18,16 @@ namespace Barotrauma
private bool getDivingGearIfNeeded; private bool getDivingGearIfNeeded;
public override float GetPriority(AIObjectiveManager objectiveManager)
{
if (objectiveManager.CurrentOrder == this)
{
return AIObjectiveManager.OrderPriority;
}
return 1.0f;
}
public override bool CanBeCompleted public override bool CanBeCompleted
{ {
get 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.AIController.SteeringManager.Reset();
character.AnimController.TargetDir = currTargetPos.X > character.SimPosition.X ? Direction.Right : Direction.Left; 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; var indoorsSteering = character.AIController.SteeringManager as IndoorsSteeringManager;
if (indoorsSteering.CurrentPath==null || indoorsSteering.CurrentPath.Unreachable) if (indoorsSteering.CurrentPath == null || indoorsSteering.CurrentPath.Unreachable)
{ {
indoorsSteering.SteeringWander(); indoorsSteering.SteeringWander();
} }
@@ -130,7 +140,7 @@ namespace Barotrauma
if (item.IsInsideTrigger(character.WorldPosition)) completed = true; 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(); if (completed) character.AIController.SteeringManager.Reset();
@@ -9,15 +9,21 @@ namespace Barotrauma
{ {
const float WallAvoidDistance = 150.0f; const float WallAvoidDistance = 150.0f;
AITarget currentTarget; private AITarget currentTarget;
private float newTargetTimer; private float newTargetTimer;
private AIObjectiveFindSafety findSafety;
public AIObjectiveIdle(Character character) : base(character, "") 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; return 1.0f;
} }
@@ -32,6 +38,14 @@ namespace Barotrauma
return; 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) if (newTargetTimer <= 0.0f)
{ {
currentTarget = FindRandomTarget(); currentTarget = FindRandomTarget();
@@ -93,16 +107,9 @@ namespace Barotrauma
} }
} }
if (character.AnimController.InWater) character.AIController.SteeringManager.SteeringWander();
{ //reset vertical steering to prevent dropping down from platforms etc
character.AIController.SteeringManager.SteeringManual(deltaTime, new Vector2(0.0f, 0.5f)); character.AIController.SteeringManager.ResetY();
}
else
{
character.AIController.SteeringManager.SteeringWander();
//reset vertical steering to prevent dropping down from platforms etc
character.AIController.SteeringManager.ResetY();
}
return; return;
} }
@@ -11,15 +11,17 @@ namespace Barotrauma
private Character character; private Character character;
private AIObjective currentObjective; private AIObjective currentOrder;
public AIObjective CurrentOrder
{
get { return currentOrder; }
}
public AIObjective CurrentObjective public AIObjective CurrentObjective
{ {
get get;
{ private set;
if (currentObjective != null) return currentObjective;
return objectives.Any() ? objectives[0] : null;
}
} }
public AIObjectiveManager(Character character) public AIObjectiveManager(Character character)
@@ -47,8 +49,13 @@ namespace Barotrauma
public float GetCurrentPriority(Character character) public float GetCurrentPriority(Character character)
{ {
if (currentObjective != null) return OrderPriority; if (CurrentOrder != null &&
return (CurrentObjective == null) ? 0.0f : CurrentObjective.GetPriority(character); (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() public void UpdateObjectives()
@@ -59,43 +66,46 @@ namespace Barotrauma
objectives = objectives.FindAll(o => !o.IsCompleted() && o.CanBeCompleted); objectives = objectives.FindAll(o => !o.IsCompleted() && o.CanBeCompleted);
//sort objectives according to priority //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) 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; return;
} }
if (!objectives.Any()) return; if (!objectives.Any()) return;
objectives[0].TryComplete(deltaTime); objectives[0].TryComplete(deltaTime);
CurrentObjective = objectives[0];
} }
public void SetOrder(Order order, string option) public void SetOrder(Order order, string option)
{ {
if (order == null) return; if (order == null) return;
currentObjective = null; currentOrder = null;
switch (order.Name.ToLowerInvariant()) switch (order.Name.ToLowerInvariant())
{ {
case "follow": case "follow":
currentObjective = new AIObjectiveGoTo(Character.Controlled, character, true); currentOrder = new AIObjectiveGoTo(Character.Controlled, character, true);
break; break;
case "wait": case "wait":
currentObjective = new AIObjectiveGoTo(character, character, true); currentOrder = new AIObjectiveGoTo(character, character, true);
break; break;
case "fixleaks": case "fixleaks":
case "fix leaks": case "fix leaks":
currentObjective = new AIObjectiveFixLeaks(character); currentOrder = new AIObjectiveFixLeaks(character);
break; break;
default: default:
if (order.TargetItem == null) return; 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; break;
} }
@@ -1,5 +1,6 @@
using Barotrauma.Items.Components; using Barotrauma.Items.Components;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Barotrauma namespace Barotrauma
@@ -14,6 +15,8 @@ namespace Barotrauma
private bool canBeCompleted; private bool canBeCompleted;
private bool requireEquip;
public override bool CanBeCompleted public override bool CanBeCompleted
{ {
get get
@@ -27,11 +30,21 @@ namespace Barotrauma
get { return operateTarget; } get { return operateTarget; }
} }
public AIObjectiveOperateItem(ItemComponent item, Character character, string option, Entity operateTarget = null, bool useController = false) public override float GetPriority(AIObjectiveManager objectiveManager)
:base (character, option) {
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.component = item;
this.requireEquip = requireEquip;
this.operateTarget = operateTarget; this.operateTarget = operateTarget;
if (useController) if (useController)
@@ -72,6 +85,43 @@ namespace Barotrauma
} }
else 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<Holdable>();
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>() { 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; if (component.AIOperate(deltaTime, character, this)) isCompleted = true;
} }
} }
@@ -3,7 +3,7 @@ using System.Diagnostics;
namespace Barotrauma namespace Barotrauma
{ {
class AIObjectiveRescue : AIObjective /*class AIObjectiveRescue : AIObjective
{ {
private readonly Character targetCharacter; private readonly Character targetCharacter;
@@ -30,5 +30,5 @@ namespace Barotrauma
return targetCharacter.IsDead ? 1000.0f / distance : 10000.0f / distance; return targetCharacter.IsDead ? 1000.0f / distance : 10000.0f / distance;
} }
} }*/
} }
@@ -3,7 +3,7 @@ using System.Linq;
namespace Barotrauma namespace Barotrauma
{ {
class AIObjectiveRescueAll : AIObjective /*class AIObjectiveRescueAll : AIObjective
{ {
private List<Character> rescueTargets; private List<Character> rescueTargets;
@@ -44,5 +44,5 @@ namespace Barotrauma
AddSubObjective(new AIObjectiveRescue(character, target)); AddSubObjective(new AIObjectiveRescue(character, target));
} }
} }
} }*/
} }
@@ -372,7 +372,7 @@ namespace Barotrauma
if (!MathUtils.IsValid(value)) return; if (!MathUtils.IsValid(value)) return;
if (GameMain.Client != null) 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; //if (newBleeding == bleeding) return;
bleeding = newBleeding; bleeding = newBleeding;
@@ -465,6 +465,12 @@ namespace Barotrauma
get { return focusedItem; } get { return focusedItem; }
} }
public Item PickingItem
{
get;
set;
}
public virtual AIController AIController public virtual AIController AIController
{ {
get { return null; } get { return null; }
@@ -13,7 +13,6 @@ namespace Barotrauma.Items.Components
private float pickTimer; private float pickTimer;
public List<InvSlotType> AllowedSlots public List<InvSlotType> AllowedSlots
{ {
get { return allowedSlots; } get { return allowedSlots; }
@@ -55,13 +54,15 @@ namespace Barotrauma.Items.Components
public override bool Pick(Character picker) public override bool Pick(Character picker)
{ {
//return if someone is already trying to pick the item //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 (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; return false;
} }
else else
@@ -104,6 +105,8 @@ namespace Barotrauma.Items.Components
private IEnumerable<object> WaitForPick(Character picker, float requiredTime) private IEnumerable<object> WaitForPick(Character picker, float requiredTime)
{ {
picker.PickingItem = item;
var leftHand = picker.AnimController.GetLimb(LimbType.LeftHand); var leftHand = picker.AnimController.GetLimb(LimbType.LeftHand);
var rightHand = picker.AnimController.GetLimb(LimbType.RightHand); var rightHand = picker.AnimController.GetLimb(LimbType.RightHand);
@@ -151,6 +154,7 @@ namespace Barotrauma.Items.Components
private void StopPicking(Character picker) private void StopPicking(Character picker)
{ {
picker.AnimController.Anim = AnimController.Animation.None; picker.AnimController.Anim = AnimController.Animation.None;
picker.PickingItem = null;
pickTimer = 0.0f; pickTimer = 0.0f;
} }
@@ -104,10 +104,6 @@ namespace Barotrauma.Items.Components
if (character == null) return false; if (character == null) return false;
if (!character.IsKeyDown(InputType.Aim)) return false; if (!character.IsKeyDown(InputType.Aim)) return false;
//if (DoesUseFail(Character)) return false;
//targetPosition = targetPosition.X, -targetPosition.Y);
float degreeOfSuccess = DegreeOfSuccess(character)/100.0f; float degreeOfSuccess = DegreeOfSuccess(character)/100.0f;
if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess) if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess)
@@ -258,9 +258,9 @@ namespace Barotrauma.Items.Components
if (batteryToLoad == null) return true; if (batteryToLoad == null) return true;
if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed*0.4f) if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f)
{ {
objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, "")); objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, "", false));
return false; return false;
} }
} }
@@ -179,7 +179,7 @@ namespace Barotrauma.Networking
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red); DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
return; return;
} }
Client nameTaken = ConnectedClients.Find(c => c.Name.ToLower() == clName.ToLower()); Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));
if (nameTaken != null) if (nameTaken != null)
{ {
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString()) if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())