diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj
index 0beadea18..f75ce7183 100644
--- a/Subsurface/Barotrauma.csproj
+++ b/Subsurface/Barotrauma.csproj
@@ -60,6 +60,10 @@
+
+
+
+
diff --git a/Subsurface/Source/Characters/AI/AIController.cs b/Subsurface/Source/Characters/AI/AIController.cs
index 5ecd56a8b..d0991bba7 100644
--- a/Subsurface/Source/Characters/AI/AIController.cs
+++ b/Subsurface/Source/Characters/AI/AIController.cs
@@ -16,6 +16,11 @@ namespace Barotrauma
protected SteeringManager steeringManager;
+ public SteeringManager SteeringManager
+ {
+ get { return steeringManager; }
+ }
+
public Vector2 Steering
{
get { return Character.AnimController.TargetMovement; }
@@ -41,8 +46,6 @@ namespace Barotrauma
public AIController (Character c)
{
Character = c;
-
- steeringManager = new SteeringManager(this);
}
public virtual void DebugDraw(SpriteBatch spriteBatch) { }
diff --git a/Subsurface/Source/Characters/AI/EnemyAIController.cs b/Subsurface/Source/Characters/AI/EnemyAIController.cs
index c692e491e..8e57c410e 100644
--- a/Subsurface/Source/Characters/AI/EnemyAIController.cs
+++ b/Subsurface/Source/Characters/AI/EnemyAIController.cs
@@ -80,6 +80,8 @@ namespace Barotrauma
sight = ToolBox.GetAttributeFloat(aiElement, "sight", 0.0f);
hearing = ToolBox.GetAttributeFloat(aiElement, "hearing", 0.0f);
+ steeringManager = new SteeringManager(this);
+
state = AiState.None;
}
diff --git a/Subsurface/Source/Characters/AI/HumanAIController.cs b/Subsurface/Source/Characters/AI/HumanAIController.cs
new file mode 100644
index 000000000..e67a0d049
--- /dev/null
+++ b/Subsurface/Source/Characters/AI/HumanAIController.cs
@@ -0,0 +1,89 @@
+using FarseerPhysics;
+using Microsoft.Xna.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Barotrauma
+{
+ class HumanAIController : AIController
+ {
+ const float UpdateObjectiveInterval = 0.5f;
+
+ private AIObjectiveManager objectiveManager;
+
+ private AITarget selectedAiTarget;
+
+ private float updateObjectiveTimer;
+
+ public HumanAIController(Character c) : base(c)
+ {
+ steeringManager = new PathSteeringManager(this);
+
+ objectiveManager = new AIObjectiveManager(c);
+ objectiveManager.AddObjective(new AIObjectiveFindSafety());
+ }
+
+ public override void Update(float deltaTime)
+ {
+ if (updateObjectiveTimer>0.0f)
+ {
+ updateObjectiveTimer -= deltaTime;
+ }
+ else
+ {
+ objectiveManager.UpdateObjectives();
+ updateObjectiveTimer = UpdateObjectiveInterval;
+ }
+
+ objectiveManager.DoCurrentObjective(deltaTime);
+
+ //if (Character.Controlled != null)
+ //{
+ // steeringManager.SteeringSeek(Character.Controlled.Position);
+ //}
+
+ Character.AnimController.IgnorePlatforms = (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X));
+
+ if (Math.Abs(Character.AnimController.TargetMovement.X)>0.1f)
+ {
+ Character.AnimController.TargetDir = Character.AnimController.TargetMovement.X > 0.0f ? Direction.Right : Direction.Left;
+ }
+
+ steeringManager.Update();
+ }
+
+ public override void SelectTarget(AITarget target)
+ {
+ selectedAiTarget = target;
+ }
+
+ public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
+ {
+
+ if (selectedAiTarget != null)
+ {
+ GUI.DrawLine(spriteBatch, new Vector2(Character.Position.X, -Character.Position.Y), ConvertUnits.ToDisplayUnits(new Vector2(selectedAiTarget.Position.X, -selectedAiTarget.Position.Y)), Color.Red);
+ }
+
+ PathSteeringManager pathSteering = steeringManager as PathSteeringManager;
+ if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode==null) return;
+
+ GUI.DrawLine(spriteBatch,
+ new Vector2(Character.Position.X, -Character.Position.Y),
+ new Vector2(pathSteering.CurrentPath.CurrentNode.Position.X, -pathSteering.CurrentPath.CurrentNode.Position.Y),
+ Color.LightGreen);
+
+
+ for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
+ {
+ GUI.DrawLine(spriteBatch,
+ new Vector2(pathSteering.CurrentPath.Nodes[i].Position.X, -pathSteering.CurrentPath.Nodes[i].Position.Y),
+ new Vector2(pathSteering.CurrentPath.Nodes[i - 1].Position.X, -pathSteering.CurrentPath.Nodes[i-1].Position.Y),
+ Color.LightGreen);
+ }
+
+ }
+ }
+}
diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjective.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjective.cs
index e00457bb8..420d1441c 100644
--- a/Subsurface/Source/Characters/AI/Objectives/AIObjective.cs
+++ b/Subsurface/Source/Characters/AI/Objectives/AIObjective.cs
@@ -9,6 +9,8 @@ namespace Barotrauma
{
protected List subObjectives;
+ protected float priority;
+
public virtual bool IsCompleted()
{
return false;
@@ -21,7 +23,7 @@ namespace Barotrauma
///
/// makes the character act according to the objective, or according to any subobjectives that
- /// need to be completed before this one (starting from the one with the highest priority)
+ /// need to be completed before this one
///
/// the character who's trying to achieve the objective
public void TryComplete(float deltaTime, Character character)
@@ -38,5 +40,15 @@ namespace Barotrauma
}
protected virtual void Act(float deltaTime, Character character) { }
+
+ public virtual float GetPriority(Character character)
+ {
+ return 0.0f;
+ }
+
+ public virtual bool IsDuplicate(AIObjective otherObjective)
+ {
+ return true;
+ }
}
}
diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
new file mode 100644
index 000000000..e79d065a3
--- /dev/null
+++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs
@@ -0,0 +1,89 @@
+using Microsoft.Xna.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Barotrauma
+{
+ class AIObjectiveFindSafety : AIObjective
+ {
+ const float SearchHullInterval = 1.0f;
+ const float MinSafety = 50.0f;
+
+ AIObjectiveGoTo gotoObjective;
+
+ float currenthullSafety;
+
+ float searchHullTimer;
+
+ protected override void Act(float deltaTime, Character character)
+ {
+ if (character.AnimController.CurrentHull == null || GetHullSafety(character.AnimController.CurrentHull) > MinSafety)
+ {
+ character.AIController.SteeringManager.SteeringSeek(character.AnimController.CurrentHull.Position);
+
+ gotoObjective = null;
+ return;
+ }
+
+ if (searchHullTimer>0.0f)
+ {
+ searchHullTimer -= deltaTime;
+ return;
+ }
+
+ searchHullTimer = SearchHullInterval;
+
+ Hull bestHull = null;
+ float bestValue = currenthullSafety;
+
+ foreach (Hull hull in Hull.hullList)
+ {
+ if (hull == character.AnimController.CurrentHull) continue;
+
+ float hullValue = GetHullSafety(hull);
+ 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);
+
+ if (bestHull==null || hullValue > bestValue)
+ {
+ bestHull = hull;
+ bestValue = hullValue;
+ }
+ }
+
+ if (bestHull != null)
+ {
+ gotoObjective = new AIObjectiveGoTo(bestHull.AiTarget, character);
+ //character.AIController.SelectTarget(bestHull.AiTarget);
+ }
+
+ gotoObjective.TryComplete(deltaTime, character);
+ }
+
+ public override float GetPriority(Character character)
+ {
+ if (character.AnimController.CurrentHull == null) return 0.0f;
+ currenthullSafety = GetHullSafety(character.AnimController.CurrentHull);
+ priority = 100.0f - currenthullSafety;
+ return priority;
+ }
+
+ private float GetHullSafety(Hull hull)
+ {
+ float waterPercentage = (hull.Volume / hull.FullVolume)*100.0f;
+ float fireAmount = 0.0f;
+
+ foreach (FireSource fireSource in hull.FireSources)
+ {
+ fireAmount += fireSource.Size.X;
+ }
+
+ float safety = 100.0f - fireAmount - waterPercentage;
+ if (hull.OxygenPercentage < 30.0f) safety -= (30.0f-hull.OxygenPercentage)*3.0f;
+
+ return safety;
+ }
+ }
+}
diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs
new file mode 100644
index 000000000..e8bd7d3ff
--- /dev/null
+++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs
@@ -0,0 +1,33 @@
+using Barotrauma.Items.Components;
+using FarseerPhysics;
+using Microsoft.Xna.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Barotrauma
+{
+ class AIObjectiveGoTo : AIObjective
+ {
+ AITarget target;
+
+ private Character character;
+
+ public AIObjectiveGoTo(AITarget target, Character character)
+ {
+ this.character = character;
+ this.target = target;
+
+ }
+
+ protected override void Act(float deltaTime, Character character)
+ {
+ if (target == null) return;
+
+ character.AIController.SelectTarget(target);
+
+ character.AIController.SteeringManager.SteeringSeek(ConvertUnits.ToDisplayUnits(target.Position));
+ }
+ }
+}
diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs
new file mode 100644
index 000000000..68d4f82ea
--- /dev/null
+++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Barotrauma
+{
+ class AIObjectiveManager
+ {
+ private List objectives;
+
+ private Character character;
+
+ public AIObjectiveManager(Character character)
+ {
+ this.character = character;
+
+ objectives = new List();
+ }
+
+ public void AddObjective(AIObjective objective)
+ {
+ if (objectives.Find(o => o.IsDuplicate(objective)) != null) return;
+
+ objectives.Add(objective);
+ }
+
+ public void UpdateObjectives()
+ {
+ if (!objectives.Any()) return;
+
+ //remove completed objectives
+ objectives = objectives.FindAll(o => !o.IsCompleted());
+
+ //sort objectives according to priority
+ objectives.Sort((x, y) => x.GetPriority(character).CompareTo(y.GetPriority(character)));
+
+ }
+
+ public void DoCurrentObjective(float deltaTime)
+ {
+ if (!objectives.Any()) return;
+ objectives[0].TryComplete(deltaTime, character);
+ }
+ }
+}
diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
index f1459595a..8da97fd54 100644
--- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
+++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveOperateItem.cs
@@ -18,5 +18,13 @@ namespace Barotrauma
{
//item.AIOperate(float deltaTime, Character character) or something
}
+
+ public override bool IsDuplicate(AIObjective otherObjective)
+ {
+ AIObjectiveOperateItem operateItem = otherObjective as AIObjectiveOperateItem;
+ if (operateItem == null) return false;
+
+ return (operateItem.targetItem == targetItem);
+ }
}
}
diff --git a/Subsurface/Source/Characters/AI/PathFinder.cs b/Subsurface/Source/Characters/AI/PathFinder.cs
index 692b83e3c..f6fe77c3a 100644
--- a/Subsurface/Source/Characters/AI/PathFinder.cs
+++ b/Subsurface/Source/Characters/AI/PathFinder.cs
@@ -1,4 +1,5 @@
-using Microsoft.Xna.Framework;
+using FarseerPhysics;
+using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
@@ -76,6 +77,9 @@ namespace Barotrauma
class PathFinder
{
+ public delegate float GetNodePenaltyHandler(PathNode node, PathNode prevNode);
+ public GetNodePenaltyHandler GetNodePriority;
+
List nodes;
private bool insideSubmarine;
@@ -89,6 +93,9 @@ namespace Barotrauma
public SteeringPath FindPath(Vector2 start, Vector2 end)
{
+ System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
+ sw.Start();
+
float closestDist = 0.0f;
PathNode startNode = null;
foreach (PathNode node in nodes)
@@ -96,11 +103,19 @@ namespace Barotrauma
float dist = Vector2.Distance(start,node.Position);
if (dist openableButtons;
+
+ public SteeringPath CurrentPath
+ {
+ get { return currentPath; }
+ }
+
+ public PathFinder PathFinder
+ {
+ get { return pathFinder; }
+ }
+
private Vector2 currentTarget;
private float findPathTimer;
public PathSteeringManager(ISteerable host)
: base(host)
- {}
+ {
+ pathFinder = new PathFinder(WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path), true);
+ pathFinder.GetNodePriority = GetNodePriority;
+
+ character = (host as AIController).Character;
+
+ openableButtons = new List();
+ }
public override void Update(float speed = 1)
{
@@ -36,14 +58,31 @@ namespace Barotrauma
if (findPathTimer > 0.0f) return Vector2.Zero;
currentTarget = target;
- currentPath = pathFinder.FindPath(ConvertUnits.ToDisplayUnits(host.SimPosition), target);
+ currentPath = pathFinder.FindPath(host.SimPosition, ConvertUnits.ToSimUnits(target));
findPathTimer = 1.0f;
return DiffToCurrentNode();
}
+
+
+ //if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
+
+ //if (currentPath.CurrentNode.ConnectedGap != null && currentPath.CurrentNode.ConnectedGap.Open < 0.9f)
+ //{
+ foreach (Controller controller in openableButtons)
+ {
+ if (Vector2.Distance(controller.Item.SimPosition, character.SimPosition) > controller.Item.PickDistance) continue;
+
+ controller.Item.Pick(character, false, true);
+ }
+ //}
+
+
Vector2 diff = DiffToCurrentNode();
+
+ if (diff == Vector2.Zero) return -host.Steering;
return (diff == Vector2.Zero) ? Vector2.Zero : Vector2.Normalize(diff)*speed;
}
@@ -52,11 +91,61 @@ namespace Barotrauma
{
if (currentPath == null) return Vector2.Zero;
- currentPath.CheckProgress(host.SimPosition, 0.1f);
+ currentPath.CheckProgress(host.SimPosition, 0.45f);
if (currentPath.CurrentNode == null) return Vector2.Zero;
return currentPath.CurrentNode.SimPosition - host.SimPosition;
}
+
+ private float GetNodePriority(PathNode node, PathNode nextNode)
+ {
+ if (character==null) return 0.0f;
+ if (nextNode.Waypoint.ConnectedGap!=null)
+ {
+ if (nextNode.Waypoint.ConnectedGap.Open > 0.9f) return 0.0f;
+ if (nextNode.Waypoint.ConnectedGap.ConnectedDoor == null) return 100.0f;
+
+ var doorButtons = GetDoorButtons(nextNode.Waypoint.ConnectedGap.ConnectedDoor);
+ foreach (Controller button in doorButtons)
+ {
+ if (Math.Sign(button.Item.Position.X - nextNode.Waypoint.Position.X) !=
+ Math.Sign(node.Position.X - nextNode.Position.X)) continue;
+
+ if (!button.HasRequiredItems(character, false)) return 1000.0f;
+ }
+ }
+
+ return 0.0f;
+ }
+
+ private List GetDoorButtons(Door door)
+ {
+ if (door == null) return new List();
+ ConnectionPanel connectionPanel = door.Item.GetComponent();
+
+ List doorButtons = new List();
+
+ foreach (Connection c in connectionPanel.Connections)
+ {
+ foreach (Wire w in c.Wires)
+ {
+ if (w == null) continue;
+ var otherConnection = w.OtherConnection(c);
+
+ if (otherConnection.Item == door.Item || otherConnection == null) continue;
+
+ var controller = otherConnection.Item.GetComponent();
+ if (controller != null)
+ {
+ doorButtons.Add(controller);
+ if (!openableButtons.Contains(controller)) openableButtons.Add(controller);
+ }
+ }
+ }
+
+ return doorButtons;
+ }
}
+
}
diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs
index 21a1fa076..e4563302b 100644
--- a/Subsurface/Source/Characters/AICharacter.cs
+++ b/Subsurface/Source/Characters/AICharacter.cs
@@ -19,41 +19,45 @@ namespace Barotrauma
get { return aiController; }
}
- public AICharacter(string file) : this(file, Vector2.Zero, null)
- {
- }
+ //public AICharacter(string file) : this(file, Vector2.Zero, null)
+ //{
+ //}
- public AICharacter(string file, Vector2 position)
- : this(file, position, null)
- {
- }
+ //public AICharacter(string file, Vector2 position)
+ // : this(file, position, null)
+ //{
+ //}
- public AICharacter(CharacterInfo characterInfo, WayPoint spawnPoint, bool isNetworkPlayer = false)
- : this(characterInfo.File, spawnPoint.SimPosition, characterInfo, isNetworkPlayer)
- {
+ //public AICharacter(CharacterInfo characterInfo, WayPoint spawnPoint, bool isNetworkPlayer = false)
+ // : this(characterInfo.File, spawnPoint.SimPosition, characterInfo, isNetworkPlayer)
+ //{
- }
+ //}
- public AICharacter(CharacterInfo characterInfo, Vector2 position, bool isNetworkPlayer = false)
- : this(characterInfo.File, position, characterInfo, isNetworkPlayer)
- {
- }
+ //public AICharacter(CharacterInfo characterInfo, Vector2 position, bool isNetworkPlayer = false)
+ // : this(characterInfo.File, position, characterInfo, isNetworkPlayer)
+ //{
+ //}
public AICharacter(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false)
: base(file, position, characterInfo, isNetworkPlayer)
{
- aiController = new EnemyAIController(this, file);
-
-
if (GameMain.Client != null && GameMain.Server == null) Enabled = false;
}
+ public void SetAI(AIController aiController)
+ {
+ this.aiController = aiController;
+ }
+
public override void Update(Camera cam, float deltaTime)
{
base.Update(cam, deltaTime);
if (isDead) return;
+ if (Controlled == this) return;
+
if (soundTimer > 0)
{
soundTimer -= deltaTime;
diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs
index cfacf2c26..6c0a21867 100644
--- a/Subsurface/Source/Characters/Character.cs
+++ b/Subsurface/Source/Characters/Character.cs
@@ -257,12 +257,12 @@ namespace Barotrauma
public override Vector2 SimPosition
{
- get { return AnimController.Limbs[0].SimPosition; }
+ get { return AnimController.RefLimb.SimPosition; }
}
public Vector2 Position
{
- get { return ConvertUnits.ToDisplayUnits(AnimController.Limbs[0].SimPosition); }
+ get { return ConvertUnits.ToDisplayUnits(AnimController.RefLimb.SimPosition); }
}
static Character()
@@ -274,28 +274,53 @@ namespace Barotrauma
DeathMsg[(int)CauseOfDeath.Pressure] = "been crushed by water pressure";
DeathMsg[(int)CauseOfDeath.Burn] = "burnt to death";
}
-
- public Character(string file) : this(file, Vector2.Zero, null)
+
+ public static Character Create(string file, Vector2 position)
{
+ return Create(file, position, null);
}
- public Character(string file, Vector2 position)
- : this(file, position, null)
+ public static Character Create(CharacterInfo characterInfo, WayPoint spawnPoint, bool isNetworkPlayer = false)
{
+ return Create(characterInfo.File, spawnPoint.SimPosition, characterInfo, isNetworkPlayer);
}
- public Character(CharacterInfo characterInfo, WayPoint spawnPoint, bool isNetworkPlayer = false)
- : this(characterInfo.File, spawnPoint.SimPosition, characterInfo, isNetworkPlayer)
- {
+ public static Character Create(CharacterInfo characterInfo, Vector2 position, bool isNetworkPlayer = false)
+ {
+ return Create(characterInfo.File, position, characterInfo, isNetworkPlayer);
}
- public Character(CharacterInfo characterInfo, Vector2 position, bool isNetworkPlayer = false)
- : this(characterInfo.File, position, characterInfo, isNetworkPlayer)
+ public static Character Create(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false)
{
+ if (file != humanConfigFile)
+ {
+ var enemyCharacter = new AICharacter(file, position, characterInfo, isNetworkPlayer);
+ var ai = new EnemyAIController(enemyCharacter, file);
+ enemyCharacter.SetAI(ai);
+
+ return enemyCharacter;
+ }
+ else
+ {
+ if (isNetworkPlayer)
+ {
+ var netCharacter = new Character(file, position, characterInfo, isNetworkPlayer);
+
+ return netCharacter;
+ }
+ else
+ {
+ var character = new AICharacter(file, position, characterInfo, isNetworkPlayer);
+ var ai = new HumanAIController(character);
+ character.SetAI(ai);
+
+ return character;
+ }
+ }
}
- public Character(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false)
+ protected Character(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false)
{
keys = new Key[Enum.GetNames(typeof(InputType)).Length];
@@ -686,6 +711,8 @@ namespace Barotrauma
///
public void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam = true)
{
+ AnimController.IsStanding = true;
+
Limb head = AnimController.GetLimb(LimbType.Head);
Lights.LightManager.ViewPos = ConvertUnits.ToDisplayUnits(head.SimPosition);
@@ -873,7 +900,7 @@ namespace Barotrauma
ControlLocalPlayer(deltaTime, cam);
}
- if (!(this is AICharacter)) Control(deltaTime, cam);
+ if (controlled==this || !(this is AICharacter)) Control(deltaTime, cam);
UpdateSightRange();
if (aiTarget != null) aiTarget.SoundRange = 0.0f;
diff --git a/Subsurface/Source/Characters/Ragdoll.cs b/Subsurface/Source/Characters/Ragdoll.cs
index 0aa080fca..870e9c459 100644
--- a/Subsurface/Source/Characters/Ragdoll.cs
+++ b/Subsurface/Source/Characters/Ragdoll.cs
@@ -314,17 +314,21 @@ namespace Barotrauma
if (targetMovement.Y >= 0.0f && lowestLimb.SimPosition.Y > ConvertUnits.ToSimUnits(structure.Rect.Y - Submarine.GridSize.Y * 8.0f))
{
- stairs = null;
- return false;
+ //stairs = null;
+ //return false;
}
Limb limb = f1.Body.UserData as Limb;
- if (limb != null && (limb.type == LimbType.LeftFoot || limb.type == LimbType.RightFoot))
+ if (limb != null)// && (limb.type == LimbType.LeftFoot || limb.type == LimbType.RightFoot))
{
if (contact.Manifold.LocalNormal.Y >= 0.0f)
{
- stairs = structure;
- return true;
+ if (limb.SimPosition.Y < lowestLimb.SimPosition.Y+0.2f)
+ {
+ stairs = structure;
+ return true;
+ }
+
}
else
{
@@ -332,10 +336,6 @@ namespace Barotrauma
return false;
}
}
- else
- {
- return false;
- }
}
@@ -356,12 +356,15 @@ namespace Barotrauma
avgVelocity = avgVelocity / Limbs.Count();
float impact = Vector2.Dot((f1.Body.LinearVelocity + avgVelocity) / 2.0f, -normal);
-
+
if (GameMain.Server != null) impact = impact / 2.0f;
Limb l = (Limb)f1.Body.UserData;
- if (impact > 1.0f && l.HitSound != null && l.soundTimer <= 0.0f) l.HitSound.Play(Math.Min(impact / 5.0f, 1.0f), impact * 100.0f, l.body.FarseerBody);
+ float volume = stairs == null ? impact/5.0f : impact;
+ volume= Math.Min(impact, 1.0f);
+
+ if (impact > 0.8f && l.HitSound != null && l.soundTimer <= 0.0f) l.HitSound.Play(volume, impact * 100.0f, l.body.FarseerBody);
if (impact > l.impactTolerance)
{
diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs
index ab3363973..b245b55df 100644
--- a/Subsurface/Source/DebugConsole.cs
+++ b/Subsurface/Source/DebugConsole.cs
@@ -223,7 +223,7 @@ namespace Barotrauma
if (commands[1].ToLower()=="human")
{
WayPoint spawnPoint = WayPoint.GetRandom(SpawnType.Human);
- Character.Controlled = new Character(Character.HumanConfigFile, (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition);
+ Character.Controlled = Character.Create(Character.HumanConfigFile, (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition);
if (GameMain.GameSession != null)
{
SinglePlayerMode mode = GameMain.GameSession.gameMode as SinglePlayerMode;
@@ -235,7 +235,7 @@ namespace Barotrauma
else
{
WayPoint spawnPoint = WayPoint.GetRandom(SpawnType.Enemy);
- new AICharacter("Content/Characters/" + commands[1] + "/" + commands[1] + ".xml", (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition);
+ Character.Create("Content/Characters/" + commands[1] + "/" + commands[1] + ".xml", (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition);
}
break;
diff --git a/Subsurface/Source/Events/MonsterEvent.cs b/Subsurface/Source/Events/MonsterEvent.cs
index 7bd7bdc44..e16939bf2 100644
--- a/Subsurface/Source/Events/MonsterEvent.cs
+++ b/Subsurface/Source/Events/MonsterEvent.cs
@@ -45,7 +45,7 @@ namespace Barotrauma
position.X += Rand.Range(-0.5f, 0.5f);
position.Y += Rand.Range(-0.5f, 0.5f);
- monsters[i] = new AICharacter(characterFile, position);
+ monsters[i] = Character.Create(characterFile, position);
}
}
diff --git a/Subsurface/Source/Events/Quests/MonsterQuest.cs b/Subsurface/Source/Events/Quests/MonsterQuest.cs
index 08f308a14..860d926ed 100644
--- a/Subsurface/Source/Events/Quests/MonsterQuest.cs
+++ b/Subsurface/Source/Events/Quests/MonsterQuest.cs
@@ -31,7 +31,7 @@ namespace Barotrauma
{
Vector2 position = level.PositionsOfInterest[Rand.Int(level.PositionsOfInterest.Count, false)];
- monster = new AICharacter(monsterFile, ConvertUnits.ToSimUnits(position+level.Position));
+ monster = Character.Create(monsterFile, ConvertUnits.ToSimUnits(position+level.Position));
}
public override void Update(float deltaTime)
diff --git a/Subsurface/Source/GameSession/CrewManager.cs b/Subsurface/Source/GameSession/CrewManager.cs
index 279260332..c81d87ffb 100644
--- a/Subsurface/Source/GameSession/CrewManager.cs
+++ b/Subsurface/Source/GameSession/CrewManager.cs
@@ -199,7 +199,7 @@ namespace Barotrauma
//WayPoint randomWayPoint = WayPoint.GetRandom(SpawnType.Human);
//Vector2 position = (randomWayPoint == null) ? Vector2.Zero : randomWayPoint.SimPosition;
- Character character = new Character(characterInfos[i], waypoints[i]);
+ Character character = Character.Create(characterInfos[i], waypoints[i]);
Character.Controlled = character;
if (!character.Info.StartItemsGiven)
diff --git a/Subsurface/Source/GameSession/GameModes/TutorialMode.cs b/Subsurface/Source/GameSession/GameModes/TutorialMode.cs
index 53b0f5150..96d6fec8b 100644
--- a/Subsurface/Source/GameSession/GameModes/TutorialMode.cs
+++ b/Subsurface/Source/GameSession/GameModes/TutorialMode.cs
@@ -47,7 +47,7 @@ namespace Barotrauma
CharacterInfo charInfo = new CharacterInfo(Character.HumanConfigFile, "", Gender.None, JobPrefab.List.Find(jp => jp.Name=="Engineer"));
- Character character = new Character(charInfo, wayPoint.SimPosition);
+ Character character = Character.Create(charInfo, wayPoint.SimPosition);
Character.Controlled = character;
character.GiveJobItems(null);
@@ -331,7 +331,7 @@ namespace Barotrauma
}
yield return new WaitForSeconds(1.0f);
- var moloch = new AICharacter("Content/Characters/Moloch/moloch.xml", steering.Item.SimPosition + Vector2.UnitX * 25.0f);
+ var moloch = Character.Create("Content/Characters/Moloch/moloch.xml", steering.Item.SimPosition + Vector2.UnitX * 25.0f);
moloch.PlaySound(AIController.AiState.Attack);
yield return new WaitForSeconds(1.0f);
diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs
index 23b0a0604..eb83c9986 100644
--- a/Subsurface/Source/Items/Components/Door.cs
+++ b/Subsurface/Source/Items/Components/Door.cs
@@ -42,6 +42,7 @@ namespace Barotrauma.Items.Components
foreach (MapEntity e in item.linkedTo)
{
linkedGap = e as Gap;
+ linkedGap.ConnectedDoor = this;
if (linkedGap != null) return linkedGap;
}
linkedGap = new Gap(item.Rect);
diff --git a/Subsurface/Source/Items/Components/Holdable/Pickable.cs b/Subsurface/Source/Items/Components/Holdable/Pickable.cs
index d3b3ebd5d..d27a504e0 100644
--- a/Subsurface/Source/Items/Components/Holdable/Pickable.cs
+++ b/Subsurface/Source/Items/Components/Holdable/Pickable.cs
@@ -65,7 +65,7 @@ namespace Barotrauma.Items.Components
var connectionPanel = item.GetComponent();
if (connectionPanel!=null)
{
- foreach (Connection c in connectionPanel.connections)
+ foreach (Connection c in connectionPanel.Connections)
{
foreach (Wire w in c.Wires)
{
diff --git a/Subsurface/Source/Items/Components/Signal/Connection.cs b/Subsurface/Source/Items/Components/Signal/Connection.cs
index 3b79d54c3..1f41d7b6a 100644
--- a/Subsurface/Source/Items/Components/Signal/Connection.cs
+++ b/Subsurface/Source/Items/Components/Signal/Connection.cs
@@ -210,7 +210,7 @@ namespace Barotrauma.Items.Components
float rightWireX = x+width / 2 + wireInterval;
float leftWireX = x + width / 2 - wireInterval;
- foreach (Connection c in panel.connections)
+ foreach (Connection c in panel.Connections)
{
//if dragging a wire, let the Inventory know so that the wire can be
//dropped or dragged from the panel to the players inventory
@@ -250,7 +250,7 @@ namespace Barotrauma.Items.Components
//and the wire hasn't been connected yet, draw it on the panel
if (equippedWire!=null)
{
- if (panel.connections.Find(c => c.Wires.Contains(equippedWire)) == null)
+ if (panel.Connections.Find(c => c.Wires.Contains(equippedWire)) == null)
{
DrawWire(spriteBatch, equippedWire.Item, equippedWire.Item,
new Vector2(x + width / 2, y + height - 100),
diff --git a/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs b/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs
index 937aeeae6..06a5cb5cb 100644
--- a/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs
+++ b/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs
@@ -8,24 +8,24 @@ namespace Barotrauma.Items.Components
{
class ConnectionPanel : ItemComponent
{
- public List connections;
+ public List Connections;
Character user;
public ConnectionPanel(Item item, XElement element)
: base(item, element)
{
- connections = new List();
+ Connections = new List();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString())
{
case "input":
- connections.Add(new Connection(subElement, item));
+ Connections.Add(new Connection(subElement, item));
break;
case "output":
- connections.Add(new Connection(subElement, item));
+ Connections.Add(new Connection(subElement, item));
break;
}
}
@@ -48,7 +48,7 @@ namespace Barotrauma.Items.Components
{
XElement componentElement = base.Save(parentElement);
- foreach (Connection c in connections)
+ foreach (Connection c in Connections)
{
c.Save(componentElement);
}
@@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components
public override void OnMapLoaded()
{
- foreach (Connection c in connections)
+ foreach (Connection c in Connections)
{
c.ConnectLinked();
}
@@ -113,9 +113,9 @@ namespace Barotrauma.Items.Components
}
}
- for (int i = 0; i w != null);
message.Write((byte)wires.Length);
@@ -142,7 +142,7 @@ namespace Barotrauma.Items.Components
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetBuffer message, float sendingTime)
{
System.Diagnostics.Debug.WriteLine("connectionpanel update");
- foreach (Connection c in connections)
+ foreach (Connection c in Connections)
{
//int wireCount = c.Wires.Length;
c.ClearConnections();
diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs
index 8a09a75c8..3a9e957a5 100644
--- a/Subsurface/Source/Items/Item.cs
+++ b/Subsurface/Source/Items/Item.cs
@@ -210,7 +210,7 @@ namespace Barotrauma
{
ConnectionPanel panel = GetComponent();
if (panel == null) return null;
- return panel.connections;
+ return panel.Connections;
}
}
@@ -790,7 +790,7 @@ namespace Barotrauma
{
ConnectionPanel panel = GetComponent();
if (panel == null) return;
- foreach (Connection c in panel.connections)
+ foreach (Connection c in panel.Connections)
{
if (c.Name != connectionName) continue;
diff --git a/Subsurface/Source/Map/Gap.cs b/Subsurface/Source/Map/Gap.cs
index 4fa897c26..3a62159f0 100644
--- a/Subsurface/Source/Map/Gap.cs
+++ b/Subsurface/Source/Map/Gap.cs
@@ -5,6 +5,7 @@ using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.ObjectModel;
+using Barotrauma.Items.Components;
namespace Barotrauma
{
@@ -37,6 +38,8 @@ namespace Barotrauma
set { open = MathHelper.Clamp(value, 0.0f, 1.0f); }
}
+ public Door ConnectedDoor;
+
public Vector2 FlowForce
{
get { return flowForce*soundVolume; }
@@ -133,43 +136,6 @@ namespace Barotrauma
linkedTo.Add(hulls[0]);
if (hulls[1] != null) linkedTo.Add(hulls[1]);
- //if (hull1 != null && hull2 != null)
- //{
- // if (isHorizontal)
- // {
- // //make sure that water1 is the lefthand room
- // //or that water2 is null if the gap doesn't lead to another room
- // if (hull1.Rect.X < hull2.Rect.X)
- // {
- // linkedTo.Add(hull1);
- // linkedTo.Add(hull2);
- // }
- // else
- // {
- // linkedTo.Add(hull2);
- // linkedTo.Add(hull1);
- // }
- // }
- // else
- // {
- // //make sure that water1 is the room on the top
- // //or that water2 is null if the gap doesn't lead to another room
- // if (hull1.Rect.Y > hull2.Rect.Y)
- // {
- // linkedTo.Add(hull1);
- // linkedTo.Add(hull2);
- // }
- // else
- // {
- // linkedTo.Add(hull2);
- // linkedTo.Add(hull1);
- // }
- // }
- //}
- //else
- //{
- // linkedTo.Add(hull1);
- //}
}
public override void Draw(SpriteBatch sb, bool editing, bool back = true)
diff --git a/Subsurface/Source/Map/MapEntityPrefab.cs b/Subsurface/Source/Map/MapEntityPrefab.cs
index f553214ff..d078c0d57 100644
--- a/Subsurface/Source/Map/MapEntityPrefab.cs
+++ b/Subsurface/Source/Map/MapEntityPrefab.cs
@@ -39,6 +39,7 @@ namespace Barotrauma
public static MapEntityPrefab Selected
{
get { return selected; }
+ set { selected = value; }
}
public virtual bool IsLinkable
diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs
index cae9a77b7..d825fc3bd 100644
--- a/Subsurface/Source/Map/WayPoint.cs
+++ b/Subsurface/Source/Map/WayPoint.cs
@@ -10,7 +10,7 @@ using System.Collections.ObjectModel;
namespace Barotrauma
{
- public enum SpawnType { None, Human, Enemy, Cargo };
+ public enum SpawnType { None, Human, Enemy, Cargo, Path };
class WayPoint : MapEntity
{
public static List WayPointList = new List();
@@ -23,6 +23,12 @@ namespace Barotrauma
//only characters with this job will be spawned at the waypoint
private JobPrefab assignedJob;
+ public Gap ConnectedGap
+ {
+ get;
+ private set;
+ }
+
public SpawnType SpawnType
{
get { return spawnType; }
@@ -60,6 +66,13 @@ namespace Barotrauma
WayPointList.Add(this);
}
+ public WayPoint(Vector2 position, SpawnType spawnType, Gap gap = null)
+ :this(new Rectangle((int)position.X-3, (int)position.Y+3, 6, 6))
+ {
+ this.spawnType = spawnType;
+ ConnectedGap = gap;
+ }
+
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back=true)
{
@@ -70,6 +83,9 @@ namespace Barotrauma
Color clr = (isSelected) ? Color.Red : Color.LightGreen;
GUI.DrawRectangle(spriteBatch, new Rectangle(pos.X - rect.Width / 2, -pos.Y - rect.Height / 2, rect.Width, rect.Height), clr, true);
+
+ spriteBatch.DrawString(GUI.SmallFont, Position.ToString(), new Vector2(Position.X, -Position.Y), Color.White);
+
foreach (MapEntity e in linkedTo)
{
GUI.DrawLine(spriteBatch,
@@ -194,6 +210,120 @@ namespace Barotrauma
return editingHUD;
}
+ public static void GenerateSubWaypoints()
+ {
+ float minDist = 200.0f;
+ float heightFromFloor = 100.0f;
+
+ foreach (Hull hull in Hull.hullList)
+ {
+ WayPoint prevWaypoint = null;
+
+ if (hull.Rect.Width stairList = new List();
+ foreach (MapEntity me in MapEntity.mapEntityList)
+ {
+ Structure stairs = me as Structure;
+ if (stairs == null) continue;
+
+ if (stairs.StairDirection != Direction.None) stairList.Add(stairs);
+ }
+
+ foreach (Structure stairs in stairList)
+ {
+ WayPoint[] stairPoints = new WayPoint[2];
+
+ stairPoints[0] = new WayPoint(
+ new Vector2(stairs.Rect.X - 50.0f,
+ stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? 80 : stairs.Rect.Height) + heightFromFloor), SpawnType.Path);
+
+ stairPoints[1] = new WayPoint(
+ new Vector2(stairs.Rect.Right + 50.0f,
+ stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? stairs.Rect.Height : 80) + heightFromFloor), SpawnType.Path);
+
+ for (int i = 0; i < 2; i++ )
+ {
+ for (int dir = -1; dir <= 1; dir += 2)
+ {
+ WayPoint closest = stairPoints[i].FindClosest(dir, true, 30.0f);
+ if (closest == null) continue;
+ stairPoints[i].ConnectTo(closest);
+ }
+ }
+
+ stairPoints[0].ConnectTo(stairPoints[1]);
+ }
+
+ foreach (Gap gap in Gap.GapList)
+ {
+ if (!gap.isHorizontal) continue;
+
+ var wayPoint = new WayPoint(
+ new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height + heightFromFloor), SpawnType.Path, gap);
+
+ for (int dir = -1; dir <= 1; dir += 2)
+ {
+ WayPoint closest = wayPoint.FindClosest(dir, true, 30.0f);
+ if (closest == null) continue;
+ wayPoint.ConnectTo(closest);
+ }
+ }
+ }
+
+ private WayPoint FindClosest(int dir, bool horizontalSearch, float tolerance)
+ {
+ if (dir != -1 && dir != 1) return null;
+
+ float closestDist = 0.0f;
+ WayPoint closest = null;
+
+ if (horizontalSearch)
+ {
+ foreach (WayPoint wp in WayPointList)
+ {
+ if (wp.SpawnType != SpawnType.Path || wp == this) continue;
+
+ if (Math.Abs(wp.Position.Y - Position.Y) > tolerance) continue;
+
+ float diff = wp.Position.X - Position.X;
+ if (Math.Sign(diff) != dir) continue;
+
+ diff = Math.Abs(diff);
+ if (closest == null || diff < closestDist)
+ {
+ if (Submarine.CheckVisibility(SimPosition, wp.SimPosition) != null) continue;
+
+ closestDist = diff;
+ closest = wp;
+ }
+ }
+ }
+
+ return closest;
+ }
+
+ private void ConnectTo(WayPoint wayPoint2)
+ {
+ linkedTo.Add(wayPoint2);
+ wayPoint2.linkedTo.Add(this);
+ }
+
public static WayPoint GetRandom(SpawnType spawnType = SpawnType.None, Job assignedJob = null)
{
List wayPoints = new List();
diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs
index e5fb122e0..0194b5b11 100644
--- a/Subsurface/Source/Networking/GameClient.cs
+++ b/Subsurface/Source/Networking/GameClient.cs
@@ -751,8 +751,8 @@ namespace Barotrauma.Networking
}
Character character = (closestWaypoint == null) ?
- new Character(ch, position, !isMyCharacter) :
- new Character(ch, closestWaypoint, !isMyCharacter);
+ Character.Create(ch, position, !isMyCharacter) :
+ Character.Create(ch, closestWaypoint, !isMyCharacter);
character.ID = ID;
diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs
index 86acbfe01..9f130bf95 100644
--- a/Subsurface/Source/Networking/GameServer.cs
+++ b/Subsurface/Source/Networking/GameServer.cs
@@ -756,14 +756,14 @@ namespace Barotrauma.Networking
for (int i = 0; i < ConnectedClients.Count; i++)
{
- ConnectedClients[i].Character = new Character(
+ ConnectedClients[i].Character = Character.Create(
ConnectedClients[i].characterInfo, assignedWayPoints[i], true);
ConnectedClients[i].Character.GiveJobItems(assignedWayPoints[i]);
}
if (characterInfo != null)
{
- myCharacter = new Character(characterInfo, assignedWayPoints[assignedWayPoints.Length - 1]);
+ myCharacter = Character.Create(characterInfo, assignedWayPoints[assignedWayPoints.Length - 1]);
Character.Controlled = myCharacter;
myCharacter.GiveJobItems(assignedWayPoints[assignedWayPoints.Length - 1]);
diff --git a/Subsurface/Source/PlayerInput.cs b/Subsurface/Source/PlayerInput.cs
index 6cb886594..3d0eb8d1f 100644
--- a/Subsurface/Source/PlayerInput.cs
+++ b/Subsurface/Source/PlayerInput.cs
@@ -278,7 +278,7 @@ namespace Barotrauma
return GameMain.Config.KeyBind(inputType).IsHit();
}
- public static bool KeyDOwn(InputType inputType)
+ public static bool KeyDown(InputType inputType)
{
return GameMain.Config.KeyBind(inputType).IsDown();
}
diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs
index e20bb27b9..7ff101292 100644
--- a/Subsurface/Source/Screens/EditMapScreen.cs
+++ b/Subsurface/Source/Screens/EditMapScreen.cs
@@ -81,6 +81,9 @@ namespace Barotrauma
button = new GUIButton(new Rectangle(0, 220, 0, 20), "Character mode", Alignment.Left, GUI.Style, GUIpanel);
button.ToolTip = "Allows you to pick up and use items. Useful for things such as placing items inside closets, turning devices on/off and doing the wiring.";
button.OnClicked = ToggleCharacterMode;
+
+ button = new GUIButton(new Rectangle(0, 270, 0, 20), "Generate waypoints", Alignment.Left, GUI.Style, GUIpanel);
+ button.OnClicked = GenerateWaypoints;
GUItabs = new GUIComponent[2];
int width = 400, height = 400;
@@ -140,6 +143,8 @@ namespace Barotrauma
GUIComponent.MouseOn = null;
+ MapEntityPrefab.Selected = null;
+
if (dummyCharacter != null)
{
dummyCharacter.Remove();
@@ -152,7 +157,7 @@ namespace Barotrauma
{
if (dummyCharacter != null) dummyCharacter.Remove();
- dummyCharacter = new Character(Character.HumanConfigFile, Vector2.Zero);
+ dummyCharacter = Character.Create(Character.HumanConfigFile, Vector2.Zero);
Character.Controlled = dummyCharacter;
GameMain.World.ProcessChanges();
}
@@ -204,6 +209,12 @@ namespace Barotrauma
return true;
}
+ private bool GenerateWaypoints(GUIButton button, object obj)
+ {
+ WayPoint.GenerateSubWaypoints();
+ return true;
+ }
+
///
/// Allows the game to run logic such as updating the world,
@@ -324,10 +335,6 @@ namespace Barotrauma
}
- //if (PlayerInput.GetMouseState.LeftButton != ButtonState.Pressed)
- //{
- // Inventory.draggingItem = null;
- //}
}
else
{
@@ -336,10 +343,9 @@ namespace Barotrauma
GUI.Draw((float)deltaTime, spriteBatch, cam);
- if (!PlayerInput.LeftButtonDown()) Inventory.draggingItem = null;
+ if (!PlayerInput.LeftButtonDown()) Inventory.draggingItem = null;
spriteBatch.End();
-
}
}
}
diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo
index e6e125c33..54ca7c8c8 100644
Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ