diff --git a/Barotrauma/BarotraumaClient/ClientCode.projitems b/Barotrauma/BarotraumaClient/ClientCode.projitems
index ab5b8970a..1b79fd2eb 100644
--- a/Barotrauma/BarotraumaClient/ClientCode.projitems
+++ b/Barotrauma/BarotraumaClient/ClientCode.projitems
@@ -79,8 +79,8 @@
-
+
@@ -213,6 +213,7 @@
+
Never
diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
index def51c503..49e4b1029 100644
--- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
+++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.8.9.6")]
-[assembly: AssemblyFileVersion("0.8.9.6")]
+[assembly: AssemblyVersion("0.8.9.8")]
+[assembly: AssemblyFileVersion("0.8.9.8")]
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs
index 6a7d9ec27..318d1d048 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs
@@ -13,13 +13,39 @@ namespace Barotrauma
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
if (soundRange > 0.0f)
{
- Color color = Entity is Character ? Color.Yellow : Color.Orange;
+ Color color;
+ if (Entity is Character)
+ {
+ color = Color.Yellow;
+ }
+ else if (Entity is Item)
+ {
+ color = Color.Orange;
+ }
+ else
+ {
+ color = Color.OrangeRed;
+ }
ShapeExtensions.DrawCircle(spriteBatch, pos, SoundRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
+ ShapeExtensions.DrawCircle(spriteBatch, pos, 3, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
}
if (sightRange > 0.0f)
{
- Color color = Entity is Character ? Color.CornflowerBlue : Color.CadetBlue;
+ Color color;
+ if (Entity is Character)
+ {
+ color = Color.CornflowerBlue;
+ }
+ else if (Entity is Item)
+ {
+ color = Color.CadetBlue;
+ }
+ else
+ {
+ color = Color.WhiteSmoke;
+ }
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
+ ShapeExtensions.DrawCircle(spriteBatch, pos, 6, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
}
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs
index f80a46f5b..b20e0e7c8 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/EnemyAIController.cs
@@ -16,18 +16,17 @@ namespace Barotrauma
if (SelectedAiTarget?.Entity != null)
{
- GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.3f, 0, 5);
+ GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.5f, 0, 4);
if (wallTarget != null)
{
Vector2 wallTargetPos = wallTarget.Position;
- if (wallTarget.Structure.Submarine != null) wallTargetPos += wallTarget.Structure.Submarine.Position;
+ if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }
wallTargetPos.Y = -wallTargetPos.Y;
- GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
+ GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Orange, false);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
}
-
- GUI.Font.DrawString(spriteBatch, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red);
+ GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.FormatZeroDecimal()})", Color.Red, Color.Black);
}
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
@@ -52,24 +51,15 @@ namespace Barotrauma
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
- if (latchOntoAI != null)
+ if (LatchOntoAI != null)
{
- foreach (Joint attachJoint in latchOntoAI.AttachJoints)
+ foreach (Joint attachJoint in LatchOntoAI.AttachJoints)
{
GUI.DrawLine(spriteBatch,
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)),
- ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Orange * 0.6f, 0, 5);
+ ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Green, 0, 4);
}
- if (latchOntoAI.WallAttachPos.HasValue)
- {
- GUI.DrawLine(spriteBatch, pos,
- ConvertUnits.ToDisplayUnits(new Vector2(latchOntoAI.WallAttachPos.Value.X, -latchOntoAI.WallAttachPos.Value.Y)), Color.Orange * 0.6f, 0, 3);
- }
- }
-
- GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
-
if (LatchOntoAI.WallAttachPos.HasValue)
{
GUI.DrawLine(spriteBatch, pos,
@@ -77,22 +67,34 @@ namespace Barotrauma
}
}
- GUI.DrawLine(spriteBatch,
- new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
- new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
- Color.Orange * 0.6f, 0, 3);
-
- for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
+ if (steeringManager is IndoorsSteeringManager pathSteering)
{
- GUI.DrawLine(spriteBatch,
- new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
- new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
- Color.Orange * 0.6f, 0, 3);
+ var path = pathSteering.CurrentPath;
+ if (path != null)
+ {
+ if (path.CurrentNode != null)
+ {
+ GUI.DrawLine(spriteBatch, pos,
+ new Vector2(path.CurrentNode.DrawPosition.X, -path.CurrentNode.DrawPosition.Y),
+ Color.DarkViolet, 0, 3);
- GUI.SmallFont.DrawString(spriteBatch,
- pathSteering.CurrentPath.Nodes[i].ID.ToString(),
- new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10),
- Color.LightGreen);
+ GUI.DrawString(spriteBatch, pos - new Vector2(0, 100), "Path cost: " + path.Cost.FormatZeroDecimal(), Color.White, Color.Black * 0.5f);
+ }
+ for (int i = 1; i < path.Nodes.Count; i++)
+ {
+ var previousNode = path.Nodes[i - 1];
+ var currentNode = path.Nodes[i];
+ GUI.DrawLine(spriteBatch,
+ new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y),
+ new Vector2(previousNode.DrawPosition.X, -previousNode.DrawPosition.Y),
+ Color.Red * 0.5f, 0, 3);
+
+ GUI.SmallFont.DrawString(spriteBatch,
+ currentNode.ID.ToString(),
+ new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
+ Color.Red);
+ }
+ }
}
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs
index b588b93a4..28686501e 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/HumanAIController.cs
@@ -75,11 +75,12 @@ namespace Barotrauma
GUI.SmallFont.DrawString(spriteBatch,
currentNode.ID.ToString(),
- new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y - 10),
- Color.LightGreen);
+ new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
+ Color.SkyBlue);
}
}
}
+ GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
//if (Character.IsKeyDown(InputType.Aim))
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs
index c2761aeaf..c6f95eda7 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs
@@ -88,13 +88,13 @@ namespace Barotrauma
Collider.AngularVelocity = newAngularVelocity;
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
- float errorTolerance = character.AllowInput ? 0.01f : 0.2f;
+ float errorTolerance = character.AllowInput ? 0.01f : 0.1f;
if (distSqrd > errorTolerance)
{
if (distSqrd > 10.0f || !character.AllowInput)
{
Collider.TargetRotation = newRotation;
- SetPosition(newPosition, lerp: distSqrd < 5.0f);
+ SetPosition(newPosition, lerp: distSqrd < 1.0f);
}
else
{
@@ -108,15 +108,8 @@ namespace Barotrauma
// -> we need to correct it manually
if (!character.AllowInput)
{
- float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition);
- float mainLimbErrorTolerance = 0.1f;
- //if the main limb is roughly at the correct position and the collider isn't moving (much at least),
- //don't attempt to correct the position.
- if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f)
- {
- MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
- MainLimb.PullJointEnabled = true;
- }
+ MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
+ MainLimb.PullJointEnabled = true;
}
}
character.MemLocalState.Clear();
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs
index 615423b53..79abaed11 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs
@@ -224,6 +224,20 @@ namespace Barotrauma
}
}
+ if (SelectedConstruction != null && SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)))
+ {
+ if (GameMain.Client != null)
+ {
+ //emulate a Select input to get the character to deselect the item server-side
+ keys[(int)InputType.Select].Hit = true;
+ }
+ //reset focus to prevent us from accidentally interacting with another entity
+ focusedItem = null;
+ focusedCharacter = null;
+ findFocusedTimer = 0.2f;
+ SelectedConstruction = null;
+ }
+
DoInteractionUpdate(deltaTime, mouseSimPos);
}
@@ -327,6 +341,8 @@ namespace Barotrauma
debugInteractablesAtCursor.Clear();
debugInteractablesNearCursor.Clear();
+ bool draggingItemToWorld = CharacterInventory.DraggingItemToWorld;
+
//reduce the amount of aim assist if an item has been selected
//= can't switch selection to another item without deselecting the current one first UNLESS the cursor is directly on the item
//otherwise it would be too easy to accidentally switch the selected item when rewiring items
@@ -348,6 +364,15 @@ namespace Barotrauma
if (item.body != null && !item.body.Enabled) continue;
if (item.ParentInventory != null) continue;
if (ignoredItems != null && ignoredItems.Contains(item)) continue;
+
+ if (draggingItemToWorld)
+ {
+ if (item.OwnInventory == null ||
+ !item.OwnInventory.CanBePut(CharacterInventory.draggingItem))
+ {
+ continue;
+ }
+ }
float distanceToItem = float.PositiveInfinity;
if (item.IsInsideTrigger(displayPosition, out Rectangle transformedTrigger))
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs
index fd0af8cf0..a2137e660 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs
@@ -248,7 +248,7 @@ namespace Barotrauma
scale: scale);
}
- if (!GUI.DisableItemHighlights)
+ if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
{
var hudTexts = focusedItem.GetHUDTexts(character);
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs
index a4eb436a9..e01a3dd2b 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs
@@ -241,10 +241,12 @@ namespace Barotrauma
if (!string.IsNullOrEmpty(jobIdentifier))
{
jobPrefab = JobPrefab.List.Find(jp => jp.Identifier == jobIdentifier);
- for (int i = 0; i < jobPrefab.Skills.Count; i++)
+ byte skillCount = inc.ReadByte();
+ for (int i = 0; i < skillCount; i++)
{
+ string skillIdentifier = inc.ReadString();
float skillLevel = inc.ReadSingle();
- skillLevels.Add(jobPrefab.Skills[i].Identifier, skillLevel);
+ skillLevels.Add(skillIdentifier, skillLevel);
}
}
@@ -254,7 +256,6 @@ namespace Barotrauma
ID = infoID,
};
ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
- System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count);
if (ch.Job != null)
{
foreach (KeyValuePair skill in skillLevels)
@@ -262,11 +263,12 @@ namespace Barotrauma
Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key);
if (matchingSkill == null)
{
- DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\"");
+ ch.Job.Skills.Add(new Skill(skill.Key, skill.Value));
continue;
}
matchingSkill.Level = skill.Value;
}
+ ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier));
}
return ch;
}
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs
index c53b261fa..5753c1c97 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs
@@ -3,7 +3,6 @@ using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
-using System.Collections.Generic;
namespace Barotrauma
{
diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs
index 04cb8c620..777bc7775 100644
--- a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs
+++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs
@@ -68,6 +68,14 @@ namespace Barotrauma
private float dropItemAnimDuration = 0.5f;
private float dropItemAnimTimer;
+
+ public Item DroppedItem
+ {
+ get
+ {
+ return droppedItem;
+ }
+ }
private Item droppedItem;
private GUIComponent draggingMed;
@@ -100,13 +108,15 @@ namespace Barotrauma
if (openHealthWindow == value) return;
if (value != null && !value.UseHealthWindow) return;
+ var prevOpenHealthWindow = openHealthWindow;
+
openHealthWindow = value;
toggledThisFrame = true;
if (Character.Controlled == null) { return; }
if (value == null &&
Character.Controlled?.SelectedCharacter?.CharacterHealth != null &&
- Character.Controlled.SelectedCharacter.CharacterHealth == openHealthWindow &&
+ Character.Controlled.SelectedCharacter.CharacterHealth == prevOpenHealthWindow &&
!Character.Controlled.SelectedCharacter.CanInventoryBeAccessed)
{
Character.Controlled.DeselectCharacter();
@@ -537,11 +547,13 @@ namespace Barotrauma
}
if (PlayerInput.KeyHit(InputType.Health) && GUI.KeyboardDispatcher.Subscriber == null &&
- Character.AllowInput && Character.FocusedCharacter == null && !toggledThisFrame)
+ Character.Controlled.AllowInput && !toggledThisFrame)
{
if (openHealthWindow != null)
+ {
OpenHealthWindow = null;
- else
+ }
+ else if (Character.Controlled == Character && Character.Controlled.FocusedCharacter == null)
{
OpenHealthWindow = this;
forceAfflictionContainerUpdate = true;
@@ -554,7 +566,10 @@ namespace Barotrauma
HUD.CloseHUD(HUDLayoutSettings.HealthWindowAreaLeft))
{
//emulate a Health input to get the character to deselect the item server-side
- Character.Keys[(int)InputType.Health].Hit = true;
+ if (GameMain.Client != null)
+ {
+ Character.Controlled.Keys[(int)InputType.Health].Hit = true;
+ }
OpenHealthWindow = null;
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs
index 4d681d60b..b993f7deb 100644
--- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs
+++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs
@@ -403,6 +403,11 @@ namespace Barotrauma
AssignRelayToServer("help", false);
AssignRelayToServer("verboselogging", false);
AssignRelayToServer("freecam", false);
+#if DEBUG
+ AssignRelayToServer("simulatedlatency", false);
+ AssignRelayToServer("simulatedloss", false);
+ AssignRelayToServer("simulatedduplicateschance", false);
+#endif
commands.Add(new Command("clientlist", "", (string[] args) => { }));
AssignRelayToServer("clientlist", true);
@@ -957,6 +962,8 @@ namespace Barotrauma
}
}
}
+ element.Value = lines[i];
+ i++;
}
}, isCheat: false));
#endif
diff --git a/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs
index 308aa869f..64fecb33b 100644
--- a/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs
+++ b/Barotrauma/BarotraumaClient/Source/GUI/ChatBox.cs
@@ -178,10 +178,15 @@ namespace Barotrauma
string displayedText = message.TranslatedText;
string senderName = "";
+ Color senderColor = Color.White;
if (!string.IsNullOrWhiteSpace(message.SenderName))
{
senderName = (message.Type == ChatMessageType.Private ? "[PM] " : "") + message.SenderName;
}
+ if (message.Sender?.Info?.Job != null)
+ {
+ senderColor = Color.Lerp(message.Sender.Info.Job.Prefab.UIColor, Color.White, 0.25f);
+ }
var msgHolder = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.0f), chatBox.Content.RectTransform, Anchor.TopCenter), style: null,
color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f);
@@ -191,7 +196,7 @@ namespace Barotrauma
{
senderNameBlock = new GUITextBlock(new RectTransform(new Vector2(0.98f, 0.0f), msgHolder.RectTransform)
{ AbsoluteOffset = new Point((int)(5 * GUI.Scale), 0) },
- senderName, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
+ senderName, textColor: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
{
CanBeFocused = true
};
@@ -230,7 +235,7 @@ namespace Barotrauma
Visible = false
};
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), popupMsg.RectTransform, Anchor.TopRight),
- senderName, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
+ senderName, textColor: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
{
CanBeFocused = false
};
@@ -328,6 +333,7 @@ namespace Barotrauma
var popupMsg = popupMessages.Count > 0 ? popupMessages.Peek() : null;
if (popupMsg != null)
{
+ int offset = -popupMsg.Rect.Width - toggleButton.Rect.Width * 2 - (int)(50 * GUI.Scale) - (guiFrame.Rect.X - GameMain.GraphicsWidth);
popupMsg.Visible = true;
//popup messages appear and disappear faster when there's more pending messages
popupMessageTimer += deltaTime * popupMessages.Count * popupMessages.Count;
@@ -335,7 +341,7 @@ namespace Barotrauma
{
//move the message out of the screen and delete it
popupMsg.RectTransform.ScreenSpaceOffset =
- new Point((int)MathHelper.SmoothStep(-popupMsg.Rect.Width - toggleButton.Rect.Width * 2, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
+ new Point((int)MathHelper.SmoothStep(offset, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
if (popupMessageTimer > PopupMessageDuration + 1.0f)
{
popupMessageTimer = 0.0f;
@@ -347,7 +353,7 @@ namespace Barotrauma
{
//move the message on the screen
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
- (int)MathHelper.SmoothStep(0, -popupMsg.Rect.Width - toggleButton.Rect.Width * 2 - (int)(35 * GUI.Scale), popupMessageTimer * 5.0f), 0);
+ (int)MathHelper.SmoothStep(0, offset, popupMessageTimer * 5.0f), 0);
}
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs
index cd8a792c0..ec5b88851 100644
--- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs
+++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs
@@ -56,7 +56,7 @@ namespace Barotrauma
private static List messages = new List();
private static Sound[] sounds;
private static bool pauseMenuOpen, settingsMenuOpen;
- private static GUIFrame pauseMenu;
+ public static GUIFrame PauseMenu { get; private set; }
private static Sprite arrow, lockIcon, checkmarkIcon, timerIcon;
public static KeyboardDispatcher KeyboardDispatcher { get; set; }
@@ -69,6 +69,9 @@ namespace Barotrauma
public static ScalableFont Font => Style?.Font;
public static ScalableFont SmallFont => Style?.SmallFont;
public static ScalableFont LargeFont => Style?.LargeFont;
+ public static ScalableFont VideoTitleFont => Style?.VideoTitleFont;
+ public static ScalableFont ObjectiveTitleFont => Style?.ObjectiveTitleFont;
+ public static ScalableFont ObjectiveNameFont => Style?.ObjectiveNameFont;
public static UISprite UIGlow => Style.UIGlow;
@@ -530,14 +533,19 @@ namespace Barotrauma
if (list.Count == 0) { return; }
foreach (var item in list)
{
- int i = updateList.Count - 1;
- while (updateList[i].UpdateOrder > item.UpdateOrder)
+ int index = 0;
+ if (updateList.Count > 0)
{
- i--;
+ index = updateList.Count - 1;
+ while (updateList[index].UpdateOrder > item.UpdateOrder)
+ {
+ index--;
+ if (index == 0) { break; }
+ }
}
if (!updateListSet.Contains(item))
{
- updateList.Insert(Math.Max(i, 0), item);
+ updateList.Insert(index, item);
updateListSet.Add(item);
}
}
@@ -553,7 +561,7 @@ namespace Barotrauma
if (pauseMenuOpen)
{
- pauseMenu.AddToGUIUpdateList();
+ PauseMenu.AddToGUIUpdateList();
}
if (settingsMenuOpen)
{
@@ -648,6 +656,7 @@ namespace Barotrauma
msg.Timer -= deltaTime;
msg.Pos += msg.Velocity * deltaTime;
}
+ }
messages.RemoveAll(m => m.Timer <= 0.0f);
}
@@ -721,6 +730,10 @@ namespace Barotrauma
Vector2 textSize = font.MeasureString(text);
DrawRectangle(sb, pos - Vector2.One * backgroundPadding, textSize + Vector2.One * 2.0f * backgroundPadding, (Color)backgroundColor, true);
}
+ else
+ {
+ sb.Draw(t, new Rectangle(rect.X + thickness, rect.Y, rect.Width - thickness * 2, thickness), null, clr, 0.0f, Vector2.Zero, SpriteEffects.None, depth);
+ sb.Draw(t, new Rectangle(rect.X + thickness, rect.Y + rect.Height - thickness, rect.Width - thickness * 2, thickness), null, clr, 0.0f, Vector2.Zero, SpriteEffects.None, depth);
font.DrawString(sb, text, pos, color);
}
@@ -1412,9 +1425,9 @@ namespace Barotrauma
if (pauseMenuOpen)
{
- pauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas), style: null, color: Color.Black * 0.5f);
+ PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas), style: null, color: Color.Black * 0.5f);
- var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.3f), pauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(200, 300) });
+ var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.3f), PauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(200, 300) });
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.85f, 0.85f), pauseMenuInner.RectTransform, Anchor.Center))
{
diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs
index c7f947b4e..2b3317682 100644
--- a/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs
+++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs
@@ -12,6 +12,9 @@ namespace Barotrauma
public ScalableFont Font { get; private set; }
public ScalableFont SmallFont { get; private set; }
public ScalableFont LargeFont { get; private set; }
+ public ScalableFont VideoTitleFont { get; private set; }
+ public ScalableFont ObjectiveTitleFont { get; private set; }
+ public ScalableFont ObjectiveNameFont { get; private set; }
public Sprite CursorSprite { get; private set; }
@@ -48,6 +51,15 @@ namespace Barotrauma
case "largefont":
LargeFont = new ScalableFont(subElement, graphicsDevice);
break;
+ case "objectivetitle":
+ ObjectiveTitleFont = new ScalableFont(subElement, graphicsDevice);
+ break;
+ case "objectivename":
+ ObjectiveNameFont = new ScalableFont(subElement, graphicsDevice);
+ break;
+ case "videotitle":
+ VideoTitleFont = new ScalableFont(subElement, graphicsDevice);
+ break;
case "cursor":
CursorSprite = new Sprite(subElement);
break;
diff --git a/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs b/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs
index 199cdb9d6..1a0b79cd9 100644
--- a/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs
+++ b/Barotrauma/BarotraumaClient/Source/GUI/HUDLayoutSettings.cs
@@ -50,6 +50,11 @@ namespace Barotrauma
get; private set;
}
+ public static Rectangle ObjectiveAnchor
+ {
+ get; private set;
+ }
+
public static Rectangle InventoryAreaLower
{
get; private set;
@@ -156,6 +161,10 @@ namespace Barotrauma
new Rectangle(Padding, CrewArea.Y, chatBoxWidth, chatBoxHeight) :
new Rectangle(GameMain.GraphicsWidth - Padding - chatBoxWidth, CrewArea.Y, chatBoxWidth, chatBoxHeight);
+ int objectiveAnchorWidth = (int)(250 * GUI.Scale);
+ int objectiveAnchorOffsetY = (int)(100 * GUI.Scale);
+ ObjectiveAnchor = new Rectangle(GameMain.GraphicsWidth - Padding - objectiveAnchorWidth, CrewArea.Y + crewAreaHeight + objectiveAnchorOffsetY, objectiveAnchorWidth, 0);
+
int lowerAreaHeight = (int)Math.Min(GameMain.GraphicsHeight * 0.25f, 280);
InventoryAreaLower = new Rectangle(Padding, GameMain.GraphicsHeight - lowerAreaHeight, GameMain.GraphicsWidth - Padding * 2, lowerAreaHeight);
@@ -191,6 +200,9 @@ namespace Barotrauma
{
public static bool CloseHUD(Rectangle rect)
{
+ // Always close when hitting escape
+ if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) { return true; }
+
//don't close when the cursor is on a UI element
if (GUI.MouseOn != null) return false;
diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs
index ded8f0896..09c332ced 100644
--- a/Barotrauma/BarotraumaClient/Source/GameMain.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs
@@ -601,8 +601,10 @@ namespace Barotrauma
{
((GUIMessageBox)GUIMessageBox.VisibleBox).Close();
}
- else // Otherwise toggle pausing.
+ else if ((Character.Controlled?.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null))
+ && Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null)
{
+ // Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
}
}
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs
index 1ef20b629..0762fbd00 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs
@@ -130,7 +130,12 @@ namespace Barotrauma
{
OnEnterMessage = (textbox, text) =>
{
- if (Character.Controlled == null) { return true; }
+ if (Character.Controlled?.Info == null)
+ {
+ textbox.Deselect();
+ textbox.Text = "";
+ return true;
+ }
textbox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
@@ -976,7 +981,7 @@ namespace Barotrauma
foreach (GUIComponent c in prevCharacterListBox.Content.Children)
{
Character character = c.UserData as Character;
- if (character == null) continue;
+ if (character == null || character.IsDead || character.Removed) continue;
AddCharacter(character);
DisplayCharacterOrder(character, character.CurrentOrder);
}
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs
index 01caedf9e..b4a7414e3 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs
@@ -44,7 +44,7 @@ namespace Barotrauma
ContextualTutorial = Tutorial.Tutorials.Find(t => t is ContextualTutorial) as ContextualTutorial;
- if (ContextualTutorial.Selected && !ContextualTutorial.Initialized) // Selected when starting a new game -> initialize
+ if (ContextualTutorial.Selected) // Selected when starting a new game -> initialize
{
ContextualTutorial.Initialize();
}
diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs
index 843b7566e..292f85b37 100644
--- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs
+++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs
@@ -1,9 +1,10 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Xml.Linq;
using System;
using Microsoft.Xna.Framework;
using Barotrauma.Items.Components;
using System.Linq;
+using Microsoft.Xna.Framework.Input;
namespace Barotrauma.Tutorials
{
@@ -13,38 +14,59 @@ namespace Barotrauma.Tutorials
public static bool ContentRunning = false;
public static bool Initialized = false;
- private enum ContentTypes { None = 0, Video = 1, Text = 2 };
+ private enum ContentTypes { None = 0, Video = 1, TextOnly = 2 };
private TutorialSegment activeSegment;
private List segments;
- private SpriteSheetPlayer spriteSheetPlayer;
+ private VideoPlayer videoPlayer;
+
private Steering navConsole;
private Reactor reactor;
private Sonar sonar;
private Vector2 subStartingPosition;
private List crew;
+ private Character mechanic;
+ private Character engineer;
+ private Character injuredMember = null;
+
private List> characterTimeOnSonar;
private float requiredTimeOnSonar = 5f;
private bool started = false;
private string playableContentPath;
-
+
private float tutorialTimer;
- private float degrading2ActivationCountdown;
private bool disableTutorialOnDeficiencyFound = true;
+ private GUIFrame holderFrame, objectiveFrame;
+ private List activeObjectives = new List();
+ private string objectiveTranslated;
+
+ private float floodTutorialTimer = 0.0f;
+ private const float floodTutorialDelay = 2.0f;
+ private float medicalTutorialTimer = 0.0f;
+ private const float medicalTutorialDelay = 2.0f;
+
+ private Point screenResolution;
+ private float prevUIScale;
+
private class TutorialSegment
{
- public string Name;
+ public string Id;
+ public string Objective;
public ContentTypes ContentType;
- public XElement Content;
+ public XElement TextContent;
+ public XElement VideoContent;
public bool IsTriggered;
+ public GUIButton ReplayButton;
+ public GUITextBlock LinkedTitle, LinkedText;
public TutorialSegment(XElement config)
{
- Name = config.GetAttributeString("name", "Missing Name");
+ Id = config.GetAttributeString("id", "Missing ID");
+ Objective = TextManager.Get(config.GetAttributeString("objective", string.Empty), true);
Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType);
IsTriggered = config.GetAttributeBool("istriggered", false);
@@ -53,10 +75,11 @@ namespace Barotrauma.Tutorials
case ContentTypes.None:
break;
case ContentTypes.Video:
- Content = config.Element("Video");
+ VideoContent = config.Element("Video");
+ TextContent = config.Element("Text");
break;
- case ContentTypes.Text:
- Content = config.Element("Text");
+ case ContentTypes.TextOnly:
+ TextContent = config.Element("Text");
break;
}
}
@@ -77,17 +100,17 @@ namespace Barotrauma.Tutorials
public override void Initialize()
{
- if (Initialized) return;
- Initialized = true;
-
- base.Initialize();
- spriteSheetPlayer = new SpriteSheetPlayer();
- characterTimeOnSonar = new List>();
-
for (int i = 0; i < segments.Count; i++)
{
segments[i].IsTriggered = false;
}
+
+ if (Initialized) return;
+ Initialized = true;
+
+ base.Initialize();
+ videoPlayer = new VideoPlayer();
+ characterTimeOnSonar = new List>();
}
public void LoadPartiallyComplete(XElement element)
@@ -111,15 +134,6 @@ namespace Barotrauma.Tutorials
}
}
- private void PreloadVideoContent()
- {
- for (int i = 0; i < segments.Count; i++)
- {
- if (segments[i].ContentType != ContentTypes.Video || segments[i].IsTriggered) continue;
- spriteSheetPlayer.PreloadContent(playableContentPath, "tutorial", segments[i].Name, segments[i].Content);
- }
- }
-
public void SavePartiallyComplete(XElement element)
{
XElement tutorialElement = new XElement("contextualtutorial");
@@ -151,13 +165,13 @@ namespace Barotrauma.Tutorials
{
if (!Initialized) return;
- PreloadVideoContent();
-
base.Start();
-
+ injuredMember = null;
+ activeObjectives.Clear();
+ objectiveTranslated = TextManager.Get("Objective");
+ CreateObjectiveFrame();
activeSegment = null;
- tutorialTimer = 0.0f;
- degrading2ActivationCountdown = -1;
+ tutorialTimer = floodTutorialTimer = medicalTutorialTimer = 0.0f;
subStartingPosition = Vector2.Zero;
characterTimeOnSonar.Clear();
@@ -193,6 +207,9 @@ namespace Barotrauma.Tutorials
}
crew = GameMain.GameSession.CrewManager.GetCharacters().ToList();
+ mechanic = CrewMemberWithJob("mechanic");
+ engineer = CrewMemberWithJob("engineer");
+
Completed = true; // Trigger completed at start to prevent the contextual tutorial from automatically activating on starting new campaigns after this one
started = true;
}
@@ -208,71 +225,185 @@ namespace Barotrauma.Tutorials
public void Stop()
{
started = ContentRunning = Initialized = false;
- spriteSheetPlayer.Remove();
- spriteSheetPlayer = null;
+ videoPlayer.Remove();
+ videoPlayer = null;
characterTimeOnSonar = null;
}
+ private void CreateObjectiveFrame()
+ {
+ holderFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center));
+ objectiveFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ObjectiveAnchor, holderFrame.RectTransform), style: null);
+
+ for (int i = 0; i < activeObjectives.Count; i++)
+ {
+ CreateObjectiveGUI(activeObjectives[i], i);
+ }
+
+ screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
+ prevUIScale = GUI.Scale;
+ }
+
public override void AddToGUIUpdateList()
{
- base.AddToGUIUpdateList();
- if (spriteSheetPlayer != null)
+ if (videoPlayer != null)
{
- spriteSheetPlayer.AddToGUIUpdateList();
+ videoPlayer.AddToGUIUpdateList(order: 100);
}
+
+ if (GUI.DisableHUD) return;
+ if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
+ {
+ CreateObjectiveFrame();
+ }
+
+ if (objectiveFrame != null && activeObjectives.Count > 0)
+ {
+ objectiveFrame.AddToGUIUpdateList(order: -1);
+ }
+ base.AddToGUIUpdateList();
}
public override void Update(float deltaTime)
{
+ if (videoPlayer != null)
+ {
+ videoPlayer.Update();
+ }
+
+ if (infoBox != null)
+ {
+ if (PlayerInput.KeyHit(Keys.Enter) || PlayerInput.KeyHit(Keys.Escape))
+ {
+ CloseInfoFrame(null, null);
+ }
+ }
+
if (!started || ContentRunning) return;
deltaTime *= 0.5f;
-
+
for (int i = 0; i < segments.Count; i++)
{
- if (segments[i].IsTriggered) continue;
+ if (segments[i].IsTriggered || activeObjectives.Contains(segments[i])) continue;
if (CheckContextualTutorials(i, deltaTime)) // Found a relevant tutorial, halt finding new ones
{
break;
}
}
+
+ for (int i = 0; i < activeObjectives.Count; i++)
+ {
+ CheckActiveObjectives(activeObjectives[i], deltaTime);
+ }
+ }
+
+ private void ClosePreTextAndTriggerVideoCallback()
+ {
+ videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(activeSegment.VideoContent), new VideoPlayer.TextSettings(activeSegment.VideoContent), activeSegment.Id, true, activeSegment.Objective, CurrentSegmentStopCallback);
}
private void CurrentSegmentStopCallback()
{
+ if (!string.IsNullOrEmpty(activeSegment.Objective))
+ {
+ AddNewObjective(activeSegment);
+ }
+
activeSegment = null;
ContentRunning = false;
}
+ private void AddNewObjective(TutorialSegment segment)
+ {
+ activeObjectives.Add(segment);
+ CreateObjectiveGUI(segment, activeObjectives.Count - 1);
+ }
+
+ private void CreateObjectiveGUI(TutorialSegment segment, int index)
+ {
+ Point replayButtonSize = new Point((int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).X * GUI.Scale), (int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).Y * 1.45f * GUI.Scale));
+
+ segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopRight, Pivot.TopRight) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null);
+ segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) =>
+ {
+ ReplaySegmentVideo(segment);
+ return true;
+ };
+
+ int yOffset = (int)((GUI.ObjectiveNameFont.MeasureString(objectiveTranslated).Y / 2f + 5) * GUI.Scale);
+ segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.BottomCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, objectiveTranslated, textColor: Color.White, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight);
+ segment.LinkedText = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.TopCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, segment.Objective, textColor: new Color(4, 180, 108), font: GUI.ObjectiveNameFont, textAlignment: Alignment.CenterRight);
+
+ segment.LinkedTitle.TextScale = segment.LinkedText.TextScale = GUI.Scale;
+
+ segment.LinkedTitle.Color = segment.LinkedTitle.HoverColor = segment.LinkedTitle.PressedColor = segment.LinkedTitle.SelectedColor = Color.Transparent;
+ segment.LinkedText.Color = segment.LinkedText.HoverColor = segment.LinkedText.PressedColor = segment.LinkedText.SelectedColor = Color.Transparent;
+ segment.ReplayButton.Color = segment.ReplayButton.HoverColor = segment.ReplayButton.PressedColor = segment.ReplayButton.SelectedColor = Color.Transparent;
+ }
+
+ private void RemoveCompletedObjective(TutorialSegment objective)
+ {
+ objective.IsTriggered = true;
+
+ int checkMarkHeight = (int)(objective.ReplayButton.Rect.Height * 1.2f);
+ int checkMarkWidth = (int)(checkMarkHeight * 0.93f);
+
+ Color color = new Color(4, 180, 108);
+ RectTransform rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), objective.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft);
+ rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5, 0);
+ GUIImage checkmark = new GUIImage(rectTA, "CheckMark");
+ checkmark.Color = color;
+
+ RectTransform rectTB = new RectTransform(new Vector2(1.1f, .8f), objective.LinkedText.RectTransform, Anchor.Center, Pivot.Center);
+ GUIImage stroke = new GUIImage(rectTB, "Stroke");
+ stroke.Color = color;
+
+ CoroutineManager.StartCoroutine(WaitForObjectiveEnd(objective));
+ }
+
+ private IEnumerable