(38b5d9aad) Experimental changes to syncing ragdolled (unconscious/dead) characters: - Higher error tolerance when syncing the positions. It's often hard to get the main limb exactly to the same position as the collider, because the positions of the limbs aren't synced and the pose of the ragdoll may differ between the server and clients. Increasing the tolerance makes it less likely for dead/unconscious characters to "twitch" when the game attempts to force the main limb to the position of the collider. - If the position of the ragdoll differs from the position of the collider so much that CheckDistFromCollider disables limb collisions, apply an additional force to all limbs to force the ragdoll to the correct position. Otherwise the ragdoll can occasionally start "hanging" midair, clipping through solid objects, because the main limb's pull joint doesn't necessarily have enough force to pull the entire ragdoll up to the collider.

This commit is contained in:
Joonas Rikkonen
2019-04-01 22:47:03 +03:00
parent 11f2bf4b38
commit ec7e23061b
130 changed files with 1359 additions and 2352 deletions
@@ -79,8 +79,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\ParamsEditor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\RectTransform.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\ShapeExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\SpriteSheetPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\UISprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\VideoPlayer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\GUI\Widget.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\CharacterInventory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Door.cs" />
@@ -213,7 +213,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\DeformAnimations\SpriteDeformation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\Sprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Sprite\SpriteSheet.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\StatusEffects\StatusEffect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\LocalizationCSVtoXML.cs">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Compile>
@@ -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.8")]
[assembly: AssemblyFileVersion("0.8.9.8")]
[assembly: AssemblyVersion("0.8.9.6")]
[assembly: AssemblyFileVersion("0.8.9.6")]
@@ -13,39 +13,13 @@ namespace Barotrauma
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
if (soundRange > 0.0f)
{
Color color;
if (Entity is Character)
{
color = Color.Yellow;
}
else if (Entity is Item)
{
color = Color.Orange;
}
else
{
color = Color.OrangeRed;
}
Color color = Entity is Character ? Color.Yellow : Color.Orange;
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;
if (Entity is Character)
{
color = Color.CornflowerBlue;
}
else if (Entity is Item)
{
color = Color.CadetBlue;
}
else
{
color = Color.WhiteSmoke;
}
Color color = Entity is Character ? Color.CornflowerBlue : Color.CadetBlue;
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);
}
}
}
@@ -16,17 +16,18 @@ namespace Barotrauma
if (SelectedAiTarget?.Entity != null)
{
GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.5f, 0, 4);
GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), Color.Red * 0.3f, 0, 5);
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.Orange, false);
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.FormatZeroDecimal()})", Color.Red, Color.Black);
GUI.Font.DrawString(spriteBatch, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red);
}
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
@@ -51,15 +52,24 @@ 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.Green, 0, 4);
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Orange * 0.6f, 0, 5);
}
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,
@@ -67,34 +77,22 @@ namespace Barotrauma
}
}
if (steeringManager is IndoorsSteeringManager pathSteering)
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++)
{
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.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);
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.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.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);
@@ -75,12 +75,11 @@ namespace Barotrauma
GUI.SmallFont.DrawString(spriteBatch,
currentNode.ID.ToString(),
new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
Color.SkyBlue);
new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y - 10),
Color.LightGreen);
}
}
}
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))
@@ -88,13 +88,13 @@ namespace Barotrauma
Collider.AngularVelocity = newAngularVelocity;
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
float errorTolerance = character.AllowInput ? 0.01f : 0.1f;
float errorTolerance = character.AllowInput ? 0.01f : 0.2f;
if (distSqrd > errorTolerance)
{
if (distSqrd > 10.0f || !character.AllowInput)
{
Collider.TargetRotation = newRotation;
SetPosition(newPosition, lerp: distSqrd < 1.0f);
SetPosition(newPosition, lerp: distSqrd < 5.0f);
}
else
{
@@ -108,8 +108,15 @@ namespace Barotrauma
// -> we need to correct it manually
if (!character.AllowInput)
{
MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
MainLimb.PullJointEnabled = true;
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;
}
}
}
character.MemLocalState.Clear();
@@ -224,20 +224,6 @@ 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);
}
@@ -341,8 +327,6 @@ 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
@@ -364,15 +348,6 @@ 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))
@@ -248,7 +248,7 @@ namespace Barotrauma
scale: scale);
}
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
if (!GUI.DisableItemHighlights)
{
var hudTexts = focusedItem.GetHUDTexts(character);
@@ -241,12 +241,10 @@ namespace Barotrauma
if (!string.IsNullOrEmpty(jobIdentifier))
{
jobPrefab = JobPrefab.List.Find(jp => jp.Identifier == jobIdentifier);
byte skillCount = inc.ReadByte();
for (int i = 0; i < skillCount; i++)
for (int i = 0; i < jobPrefab.Skills.Count; i++)
{
string skillIdentifier = inc.ReadString();
float skillLevel = inc.ReadSingle();
skillLevels.Add(skillIdentifier, skillLevel);
skillLevels.Add(jobPrefab.Skills[i].Identifier, skillLevel);
}
}
@@ -256,6 +254,7 @@ 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<string, float> skill in skillLevels)
@@ -263,12 +262,11 @@ namespace Barotrauma
Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key);
if (matchingSkill == null)
{
ch.Job.Skills.Add(new Skill(skill.Key, skill.Value));
DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\"");
continue;
}
matchingSkill.Level = skill.Value;
}
ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier));
}
return ch;
}
@@ -3,6 +3,7 @@ using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Collections.Generic;
namespace Barotrauma
{
@@ -68,14 +68,6 @@ namespace Barotrauma
private float dropItemAnimDuration = 0.5f;
private float dropItemAnimTimer;
public Item DroppedItem
{
get
{
return droppedItem;
}
}
private Item droppedItem;
private GUIComponent draggingMed;
@@ -108,15 +100,13 @@ 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 == prevOpenHealthWindow &&
Character.Controlled.SelectedCharacter.CharacterHealth == openHealthWindow &&
!Character.Controlled.SelectedCharacter.CanInventoryBeAccessed)
{
Character.Controlled.DeselectCharacter();
@@ -547,13 +537,11 @@ namespace Barotrauma
}
if (PlayerInput.KeyHit(InputType.Health) && GUI.KeyboardDispatcher.Subscriber == null &&
Character.Controlled.AllowInput && !toggledThisFrame)
Character.AllowInput && Character.FocusedCharacter == null && !toggledThisFrame)
{
if (openHealthWindow != null)
{
OpenHealthWindow = null;
}
else if (Character.Controlled == Character && Character.Controlled.FocusedCharacter == null)
else
{
OpenHealthWindow = this;
forceAfflictionContainerUpdate = true;
@@ -566,10 +554,7 @@ namespace Barotrauma
HUD.CloseHUD(HUDLayoutSettings.HealthWindowAreaLeft))
{
//emulate a Health input to get the character to deselect the item server-side
if (GameMain.Client != null)
{
Character.Controlled.Keys[(int)InputType.Health].Hit = true;
}
Character.Keys[(int)InputType.Health].Hit = true;
OpenHealthWindow = null;
}
}
@@ -403,11 +403,6 @@ 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);
@@ -178,15 +178,10 @@ 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);
@@ -196,7 +191,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: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
senderName, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null)
{
CanBeFocused = true
};
@@ -235,7 +230,7 @@ namespace Barotrauma
Visible = false
};
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), popupMsg.RectTransform, Anchor.TopRight),
senderName, textColor: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
senderName, textColor: Color.White, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
{
CanBeFocused = false
};
@@ -333,7 +328,6 @@ 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;
@@ -341,7 +335,7 @@ namespace Barotrauma
{
//move the message out of the screen and delete it
popupMsg.RectTransform.ScreenSpaceOffset =
new Point((int)MathHelper.SmoothStep(offset, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
new Point((int)MathHelper.SmoothStep(-popupMsg.Rect.Width - toggleButton.Rect.Width * 2, 10, (popupMessageTimer - PopupMessageDuration) * 5.0f), 0);
if (popupMessageTimer > PopupMessageDuration + 1.0f)
{
popupMessageTimer = 0.0f;
@@ -353,7 +347,7 @@ namespace Barotrauma
{
//move the message on the screen
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
(int)MathHelper.SmoothStep(0, offset, popupMessageTimer * 5.0f), 0);
(int)MathHelper.SmoothStep(0, -popupMsg.Rect.Width - toggleButton.Rect.Width * 2 - (int)(35 * GUI.Scale), popupMessageTimer * 5.0f), 0);
}
}
}
+8 -16
View File
@@ -56,7 +56,7 @@ namespace Barotrauma
private static List<GUIMessage> messages = new List<GUIMessage>();
private static Sound[] sounds;
private static bool pauseMenuOpen, settingsMenuOpen;
public static GUIFrame PauseMenu { get; private set; }
private static GUIFrame pauseMenu;
private static Sprite arrow, lockIcon, checkmarkIcon, timerIcon;
public static KeyboardDispatcher KeyboardDispatcher { get; set; }
@@ -69,9 +69,6 @@ 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;
@@ -533,19 +530,14 @@ namespace Barotrauma
if (list.Count == 0) { return; }
foreach (var item in list)
{
int index = 0;
if (updateList.Count > 0)
int i = updateList.Count - 1;
while (updateList[i].UpdateOrder > item.UpdateOrder)
{
index = updateList.Count - 1;
while (updateList[index].UpdateOrder > item.UpdateOrder)
{
index--;
if (index == 0) { break; }
}
i--;
}
if (!updateListSet.Contains(item))
{
updateList.Insert(index, item);
updateList.Insert(Math.Max(i, 0), item);
updateListSet.Add(item);
}
}
@@ -561,7 +553,7 @@ namespace Barotrauma
if (pauseMenuOpen)
{
PauseMenu.AddToGUIUpdateList();
pauseMenu.AddToGUIUpdateList();
}
if (settingsMenuOpen)
{
@@ -1420,9 +1412,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))
{
@@ -12,9 +12,6 @@ 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; }
@@ -51,15 +48,6 @@ 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;
@@ -50,11 +50,6 @@ namespace Barotrauma
get; private set;
}
public static Rectangle ObjectiveAnchor
{
get; private set;
}
public static Rectangle InventoryAreaLower
{
get; private set;
@@ -161,10 +156,6 @@ 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);
@@ -200,9 +191,6 @@ 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;
@@ -601,10 +601,8 @@ namespace Barotrauma
{
((GUIMessageBox)GUIMessageBox.VisibleBox).Close();
}
else if ((Character.Controlled?.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null))
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null)
else // Otherwise toggle pausing.
{
// Otherwise toggle pausing, unless another window/interface is open.
GUI.TogglePauseMenu();
}
}
@@ -130,12 +130,7 @@ namespace Barotrauma
{
OnEnterMessage = (textbox, text) =>
{
if (Character.Controlled?.Info == null)
{
textbox.Deselect();
textbox.Text = "";
return true;
}
if (Character.Controlled == null) { return true; }
textbox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
@@ -981,7 +976,7 @@ namespace Barotrauma
foreach (GUIComponent c in prevCharacterListBox.Content.Children)
{
Character character = c.UserData as Character;
if (character == null || character.IsDead || character.Removed) continue;
if (character == null) continue;
AddCharacter(character);
DisplayCharacterOrder(character, character.CurrentOrder);
}
@@ -44,7 +44,7 @@ namespace Barotrauma
ContextualTutorial = Tutorial.Tutorials.Find(t => t is ContextualTutorial) as ContextualTutorial;
if (ContextualTutorial.Selected) // Selected when starting a new game -> initialize
if (ContextualTutorial.Selected && !ContextualTutorial.Initialized) // Selected when starting a new game -> initialize
{
ContextualTutorial.Initialize();
}
@@ -1,10 +1,9 @@
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
{
@@ -14,59 +13,38 @@ namespace Barotrauma.Tutorials
public static bool ContentRunning = false;
public static bool Initialized = false;
private enum ContentTypes { None = 0, Video = 1, TextOnly = 2 };
private enum ContentTypes { None = 0, Video = 1, Text = 2 };
private TutorialSegment activeSegment;
private List<TutorialSegment> segments;
private VideoPlayer videoPlayer;
private SpriteSheetPlayer spriteSheetPlayer;
private Steering navConsole;
private Reactor reactor;
private Sonar sonar;
private Vector2 subStartingPosition;
private List<Character> crew;
private Character mechanic;
private Character engineer;
private Character injuredMember = null;
private List<Pair<Character, float>> 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<TutorialSegment> activeObjectives = new List<TutorialSegment>();
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 Id;
public string Objective;
public string Name;
public ContentTypes ContentType;
public XElement TextContent;
public XElement VideoContent;
public XElement Content;
public bool IsTriggered;
public GUIButton ReplayButton;
public GUITextBlock LinkedTitle, LinkedText;
public TutorialSegment(XElement config)
{
Id = config.GetAttributeString("id", "Missing ID");
Objective = TextManager.Get(config.GetAttributeString("objective", string.Empty), true);
Name = config.GetAttributeString("name", "Missing Name");
Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType);
IsTriggered = config.GetAttributeBool("istriggered", false);
@@ -75,11 +53,10 @@ namespace Barotrauma.Tutorials
case ContentTypes.None:
break;
case ContentTypes.Video:
VideoContent = config.Element("Video");
TextContent = config.Element("Text");
Content = config.Element("Video");
break;
case ContentTypes.TextOnly:
TextContent = config.Element("Text");
case ContentTypes.Text:
Content = config.Element("Text");
break;
}
}
@@ -100,17 +77,17 @@ namespace Barotrauma.Tutorials
public override void Initialize()
{
for (int i = 0; i < segments.Count; i++)
{
segments[i].IsTriggered = false;
}
if (Initialized) return;
Initialized = true;
base.Initialize();
videoPlayer = new VideoPlayer();
spriteSheetPlayer = new SpriteSheetPlayer();
characterTimeOnSonar = new List<Pair<Character, float>>();
for (int i = 0; i < segments.Count; i++)
{
segments[i].IsTriggered = false;
}
}
public void LoadPartiallyComplete(XElement element)
@@ -134,6 +111,15 @@ 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");
@@ -165,13 +151,13 @@ namespace Barotrauma.Tutorials
{
if (!Initialized) return;
PreloadVideoContent();
base.Start();
injuredMember = null;
activeObjectives.Clear();
objectiveTranslated = TextManager.Get("Objective");
CreateObjectiveFrame();
activeSegment = null;
tutorialTimer = floodTutorialTimer = medicalTutorialTimer = 0.0f;
tutorialTimer = 0.0f;
degrading2ActivationCountdown = -1;
subStartingPosition = Vector2.Zero;
characterTimeOnSonar.Clear();
@@ -207,9 +193,6 @@ 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;
}
@@ -225,185 +208,71 @@ namespace Barotrauma.Tutorials
public void Stop()
{
started = ContentRunning = Initialized = false;
videoPlayer.Remove();
videoPlayer = null;
spriteSheetPlayer.Remove();
spriteSheetPlayer = 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()
{
if (videoPlayer != null)
{
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();
if (spriteSheetPlayer != null)
{
spriteSheetPlayer.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 || activeObjectives.Contains(segments[i])) continue;
if (segments[i].IsTriggered) 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<object> WaitForObjectiveEnd(TutorialSegment objective)
{
yield return new WaitForSeconds(2.0f);
objectiveFrame.RemoveChild(objective.ReplayButton);
activeObjectives.Remove(objective);
for (int i = 0; i < activeObjectives.Count; i++)
{
activeObjectives[i].ReplayButton.RectTransform.AbsoluteOffset = new Point(0, (activeObjectives[i].ReplayButton.Rect.Height + 20) * i);
}
}
private bool CheckContextualTutorials(int index, float deltaTime)
{
switch (index)
{
case 0: // Welcome: Game Start [Text]
if (tutorialTimer < 1.0f)
if (tutorialTimer < 0.5f)
{
tutorialTimer += deltaTime;
return false;
}
break;
case 1: // Command Reactor: 2 seconds after 'Welcome' dismissed and only if no command given to start reactor [Video]
if (!segments[0].IsTriggered) return false;
if (tutorialTimer < 3.0f)
case 1: // Command Reactor: 10 seconds after 'Welcome' dismissed and only if no command given to start reactor [Video]
if (tutorialTimer < 10.5f)
{
tutorialTimer += deltaTime;
if (HasOrder("operatereactor"))
{
segments[index].IsTriggered = true;
tutorialTimer = 2.5f;
tutorialTimer = 10.5f;
}
return false;
}
break;
case 2: // Nav Console: 2 seconds after 'Command Reactor' dismissed or if nav console is activated [Video]
if (!IsReactorPoweredUp()) return false; // Do not advance tutorial based on this segment if reactor has not been powered up
case 2: // Nav Console: 20 seconds after 'Command Reactor' dismissed or if nav console is activated [Video]
if (Character.Controlled?.SelectedConstruction != navConsole.Item)
{
if (tutorialTimer < 4.5f)
{
if (!segments[1].IsTriggered) return false; // Do not advance tutorial timer based on this segment if reactor has not been powered up
if (tutorialTimer < 30.5f)
{
tutorialTimer += deltaTime;
return false;
@@ -411,13 +280,20 @@ namespace Barotrauma.Tutorials
}
else
{
tutorialTimer = 4.5f;
}
if (!segments[1].IsTriggered || !HasOrder("operatereactor")) // If reactor has not been powered up or ordered to be, default to that one first
{
if (tutorialTimer < 10.5f)
{
tutorialTimer = 10.5f;
}
return false;
}
TriggerTutorialSegment(index, GameMain.GameSession.EndLocation.Name);
return true;
tutorialTimer = 30.5f;
}
break;
case 3: // Objective: Travel ~150 meters and while sub is not flooding [Text]
if (Vector2.Distance(subStartingPosition, Submarine.MainSub.WorldPosition) < 8000f || IsFlooding())
if (Vector2.Distance(subStartingPosition, Submarine.MainSub.WorldPosition) < 12000f || IsFlooding())
{
return false;
}
@@ -431,11 +307,6 @@ namespace Barotrauma.Tutorials
{
return false;
}
else if (floodTutorialTimer < floodTutorialDelay)
{
floodTutorialTimer += deltaTime;
return false;
}
break;
case 5: // Reactor: Player uses reactor for the first time [Video]
if (Character.Controlled?.SelectedConstruction != reactor.Item)
@@ -450,23 +321,19 @@ namespace Barotrauma.Tutorials
}
break;
case 7: // Degrading1: Any equipment degrades to 50% health or less and player has not assigned any crew to perform maintenance [Text]
if ((mechanic == null || mechanic.IsDead) && (engineer == null || engineer.IsDead)) // Both engineer and mechanic are dead or do not exist -> do not display
{
return false;
}
bool degradedEquipmentFound = false;
foreach (Item item in Item.ItemList)
{
if (!item.Repairables.Any() || item.Condition > 50.0f) continue;
if (!item.Repairables.Any() || item.ConditionPercentage > 50) continue;
degradedEquipmentFound = true;
break;
}
if (degradedEquipmentFound)
{
if (HasOrder("repairsystems", "jobspecific"))
degrading2ActivationCountdown = 5f;
if (HasOrder("repairsystems"))
{
segments[index].IsTriggered = true;
return false;
@@ -477,44 +344,43 @@ namespace Barotrauma.Tutorials
return false;
}
break;
case 8: // Medical: Crewmember is injured but not killed [Video]
if (injuredMember == null)
case 8: // Degrading2: 5 seconds after 'Degrading1' dismissed, and only if player has not assigned any crew to perform maintenance [Video]
if (degrading2ActivationCountdown == -1f)
{
for (int i = 0; i < crew.Count; i++)
return false;
}
else if (degrading2ActivationCountdown > 0.0f)
{
degrading2ActivationCountdown -= deltaTime;
if (HasOrder("repairsystems"))
{
Character member = crew[i];
if (member.Vitality < member.MaxVitality && !member.IsDead)
{
injuredMember = member;
break;
}
segments[index].IsTriggered = true;
}
return false;
}
else if (medicalTutorialTimer < medicalTutorialDelay)
break;
case 9: // Medical: Crewmember is injured but not killed [Video]
bool injuredFound = false;
for (int i = 0; i < crew.Count; i++)
{
medicalTutorialTimer += deltaTime;
return false;
Character member = crew[i];
if (member.Vitality < member.MaxVitality && !member.IsDead)
{
injuredFound = true;
break;
}
}
else
{
TriggerTutorialSegment(index, new string[] { injuredMember.Info.DisplayName,
(injuredMember.Info.Gender == Gender.Male) ? TextManager.Get("PronounPossessiveMale").ToLower() : TextManager.Get("PronounPossessiveFemale").ToLower() });
return true;
}
case 9: // Approach1: Destination is within ~100m [Video]
if (!injuredFound) return false;
break;
case 10: // Approach1: Destination is within ~100m [Video]
if (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 8000f)
{
return false;
}
else
{
TriggerTutorialSegment(index, GameMain.GameSession.EndLocation.Name);
return true;
}
case 10: // Approach2: Sub is docked [Text]
break;
case 11: // Approach2: Sub is docked [Text]
if (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0)
{
return false;
@@ -526,128 +392,11 @@ namespace Barotrauma.Tutorials
return true;
}
private bool HasObjective(string objectiveName)
{
for (int i = 0; i < activeObjectives.Count; i++)
{
if (activeObjectives[i].Id == objectiveName) return true;
}
return false;
}
private void CheckActiveObjectives(TutorialSegment objective, float deltaTime)
{
switch(objective.Id)
{
case "ReactorCommand": // Reactor commanded
if (!IsReactorPoweredUp())
{
if (!HasOrder("operatereactor")) return;
}
break;
case "NavConsole": // traveled 50 meters
if (Vector2.Distance(subStartingPosition, Submarine.MainSub.WorldPosition) < 4000f)
{
return;
}
break;
case "Flood": // Hull breaches repaired
if (IsFlooding()) return;
break;
case "Medical":
if (injuredMember != null && !injuredMember.IsDead)
{
if (injuredMember.CharacterHealth.DroppedItem == null) return;
}
break;
case "EnemyOnSonar": // Enemy dispatched
if (HasEnemyOnSonarForDuration(deltaTime))
{
return;
}
break;
case "Degrading": // Fixed
if (mechanic != null && !mechanic.IsDead)
{
HumanAIController humanAI = mechanic.AIController as HumanAIController;
if (mechanic.CurrentOrder?.AITag != "repairsystems" || humanAI.CurrentOrderOption != "jobspecific")
{
return;
}
}
if (engineer != null && !engineer.IsDead)
{
HumanAIController humanAI = engineer.AIController as HumanAIController;
if (engineer.CurrentOrder?.AITag != "repairsystems" || humanAI.CurrentOrderOption != "jobspecific")
{
return;
}
}
break;
case "Approach1": // Wait until docked
if (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0)
{
return;
}
break;
}
RemoveCompletedObjective(objective);
}
private bool IsReactorPoweredUp()
{
float load = 0.0f;
List<Connection> connections = reactor.Item.Connections;
if (connections != null && connections.Count > 0)
{
foreach (Connection connection in connections)
{
if (!connection.IsPower) continue;
foreach (Connection recipient in connection.Recipients)
{
if (!(recipient.Item is Item it)) continue;
PowerTransfer pt = it.GetComponent<PowerTransfer>();
if (pt == null) continue;
load = Math.Max(load, pt.PowerLoad);
}
}
}
return Math.Abs(load + reactor.CurrPowerConsumption) < 10;
}
private Character CrewMemberWithJob(string job)
private bool HasOrder(string aiTag)
{
for (int i = 0; i < crew.Count; i++)
{
if (crew[i].Info.Job.Name == job) return crew[i];
}
return null;
}
private bool HasOrder(string aiTag, string option = null)
{
for (int i = 0; i < crew.Count; i++)
{
if (crew[i].CurrentOrder?.AITag == aiTag)
{
if (option == null)
{
return true;
}
else
{
HumanAIController humanAI = crew[i].AIController as HumanAIController;
return humanAI.CurrentOrderOption == option;
}
}
if (crew[i].CurrentOrder?.AITag == aiTag) return true;
}
return false;
@@ -657,12 +406,10 @@ namespace Barotrauma.Tutorials
{
foreach (Gap gap in Gap.GapList)
{
if (gap.ConnectedWall == null || gap.IsRoomToRoom) continue;
if (gap.ConnectedWall == null) continue;
if (gap.ConnectedDoor != null || gap.Open <= 0.0f) continue;
if (gap.Submarine == null) continue;
if (gap.Submarine.IsOutpost) continue;
if (gap.Submarine != Submarine.MainSub) continue;
if (gap.FlowTargetHull == null || gap.FlowTargetHull.WaterPercentage <= 0.0f) continue;
return true;
}
@@ -700,51 +447,27 @@ namespace Barotrauma.Tutorials
}
}
return characterTimeOnSonar.Find(ct => ct.Second >= requiredTimeOnSonar && !ct.First.IsDead) != null;
return characterTimeOnSonar.Find(ct => ct.Second >= requiredTimeOnSonar) != null;
}
private void TriggerTutorialSegment(int index, params object[] args)
{
Inventory.draggingItem = null;
ContentRunning = true;
activeSegment = segments[index];
string tutorialText = TextManager.GetFormatted(activeSegment.TextContent.GetAttributeString("tag", ""), true, args);
string objectiveText = string.Empty;
if (!string.IsNullOrEmpty(activeSegment.Objective))
{
if (args.Length == 0)
{
objectiveText = activeSegment.Objective;
}
else
{
objectiveText = string.Format(activeSegment.Objective, args);
}
activeSegment.Objective = objectiveText;
}
else
{
activeSegment.IsTriggered = true; // Complete at this stage only if no related objective
}
activeSegment.IsTriggered = true;
switch (activeSegment.ContentType)
{
case ContentTypes.None:
break;
case ContentTypes.Video:
infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Id), tutorialText,
activeSegment.TextContent.GetAttributeInt("width", 300),
activeSegment.TextContent.GetAttributeInt("height", 80),
activeSegment.TextContent.GetAttributeString("anchor", "Center"), true, ClosePreTextAndTriggerVideoCallback);
spriteSheetPlayer.LoadContent(playableContentPath, activeSegment.Content, activeSegment.Name, true, true, CurrentSegmentStopCallback);
break;
case ContentTypes.TextOnly:
infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Id), tutorialText,
activeSegment.TextContent.GetAttributeInt("width", 300),
activeSegment.TextContent.GetAttributeInt("height", 80),
activeSegment.TextContent.GetAttributeString("anchor", "Center"), true, CurrentSegmentStopCallback);
case ContentTypes.Text:
infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Name), TextManager.GetFormatted(activeSegment.Content.GetAttributeString("tag", ""), false, args),
activeSegment.Content.GetAttributeInt("width", 300),
activeSegment.Content.GetAttributeInt("height", 80),
activeSegment.Content.GetAttributeString("anchor", "Center"), true, CurrentSegmentStopCallback);
break;
}
@@ -756,13 +479,6 @@ namespace Barotrauma.Tutorials
CoroutineManager.StartCoroutine(WaitToStop()); // Completed
}
private void ReplaySegmentVideo(TutorialSegment segment)
{
if (ContentRunning) return;
ContentRunning = true;
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false);
}
private IEnumerable<object> WaitToStop()
{
while (ContentRunning) yield return null;
@@ -121,7 +121,7 @@ namespace Barotrauma.Tutorials
public virtual void AddToGUIUpdateList()
{
if (infoBox != null) infoBox.AddToGUIUpdateList(order: 100);
if (infoBox != null) infoBox.AddToGUIUpdateList();
}
public virtual void Update(float deltaTime)
@@ -188,19 +188,17 @@ namespace Barotrauma.Tutorials
Anchor anchor = Anchor.TopRight;
Enum.TryParse(anchorStr, out anchor);
var infoBlock = new GUIFrame(new RectTransform(new Point((int)(width * GUI.Scale), (int)(height * GUI.Scale)), GUI.Canvas, anchor) { AbsoluteOffset = new Point(20) });
var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, anchor) { AbsoluteOffset = new Point(20) });
infoBlock.Flash(Color.Green);
if (title.Length > 0)
{
var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1f, .35f), infoBlock.RectTransform, Anchor.TopCenter,
Pivot.TopCenter), title, font: GUI.VideoTitleFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0));
titleBlock.TextScale = GUI.Scale;
Pivot.TopCenter), title, font: GUI.LargeFont, textAlignment: Alignment.Center);
}
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 1f), infoBlock.RectTransform, Anchor.BottomCenter),
text, wrap: true);
textBlock.TextScale = GUI.Scale;
infoBoxClosedCallback = callback;
@@ -14,13 +14,12 @@ namespace Barotrauma
{
private enum Tab
{
General,
Graphics,
Audio,
Controls,
}
private readonly Point MinSupportedResolution = new Point(1024, 540);
private GUIFrame settingsFrame;
private GUIButton applyButton;
@@ -72,79 +71,16 @@ namespace Barotrauma
private void CreateSettingsFrame()
{
settingsFrame = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), GUI.Canvas, Anchor.Center));
settingsFrame = new GUIFrame(new RectTransform(new Point(500, 500), GUI.Canvas, Anchor.Center));
var settingsFramePadding = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), settingsFrame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }, style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), settingsFrame.RectTransform),
TextManager.Get("Settings"), textAlignment: Alignment.Center, font: GUI.LargeFont);
/// General tab --------------------------------------------------------------
var leftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 1.0f), settingsFramePadding.RectTransform, Anchor.TopLeft));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform),
TextManager.Get("Settings"), textAlignment: Alignment.TopLeft, font: GUI.LargeFont);
var generalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), leftPanel.RectTransform, Anchor.TopLeft));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("ContentPackages"));
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.75f), generalLayoutGroup.RectTransform))
{
CanBeFocused = false
};
foreach (ContentPackage contentPackage in ContentPackage.List)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.067f), contentPackageList.Content.RectTransform, minSize: new Point(0, 15)), contentPackage.Name)
{
UserData = contentPackage,
OnSelected = SelectContentPackage,
Selected = SelectedContentPackages.Contains(contentPackage)
};
if (!contentPackage.IsCompatible())
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
tickBox.ToolTip = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
.Replace("[packagename]", contentPackage.Name)
.Replace("[packageversion]", contentPackage.GameVersion.ToString())
.Replace("[gameversion]", GameMain.Version.ToString());
}
else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
tickBox.ToolTip = TextManager.Get("ContentPackageMissingCoreFiles")
.Replace("[packagename]", contentPackage.Name)
.Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
}
}
new GUITextBlock(new RectTransform(new Vector2(0.92f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("Language"));
var languageDD = new GUIDropDown(new RectTransform(new Vector2(0.92f, 0.05f), generalLayoutGroup.RectTransform));
foreach (string language in TextManager.AvailableLanguages)
{
languageDD.AddItem(TextManager.Get("Language." + language), language);
}
languageDD.SelectItem(TextManager.Language);
languageDD.OnSelected = (guiComponent, obj) =>
{
string newLanguage = obj as string;
if (newLanguage == Language) return true;
UnsavedSettings = true;
Language = newLanguage;
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
return true;
};
var rightPanel = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - leftPanel.RectTransform.RelativeSize.X, 0.95f),
settingsFramePadding.RectTransform, Anchor.TopRight));
var tabButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), rightPanel.RectTransform, Anchor.TopCenter), isHorizontal: true);
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), rightPanel.RectTransform, Anchor.Center), style: null);
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.8f), settingsFrame.RectTransform, Anchor.Center)
{ RelativeOffset = new Vector2(0.0f, 0.06f) }, style: null);
var tabButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.05f), settingsFrame.RectTransform, Anchor.TopCenter)
{ RelativeOffset = new Vector2(0.0f, 0.11f) }, isHorizontal: true);
tabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length];
tabButtons = new GUIButton[tabs.Length];
@@ -168,10 +104,10 @@ namespace Barotrauma
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.CenterLeft)
{ RelativeOffset = new Vector2(0.02f, 0.0f) })
{ RelativeSpacing = 0.01f };
{ RelativeSpacing = 0.01f, Stretch = true };
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.CenterRight)
{ RelativeOffset = new Vector2(0.02f, 0.0f) })
{ RelativeSpacing = 0.01f };
{ RelativeSpacing = 0.01f, Stretch = true };
var supportedDisplayModes = new List<DisplayMode>();
foreach (DisplayMode mode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
@@ -199,7 +135,6 @@ namespace Barotrauma
foreach (DisplayMode mode in supportedDisplayModes)
{
if (mode.Width < MinSupportedResolution.X || mode.Height < MinSupportedResolution.Y) { continue; }
resolutionDD.AddItem(mode.Width + "x" + mode.Height, mode);
if (GraphicsWidth == mode.Width && GraphicsHeight == mode.Height) resolutionDD.SelectItem(mode);
}
@@ -238,6 +173,9 @@ namespace Barotrauma
return true;
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), style: null);
GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("EnableVSync"))
{
ToolTip = TextManager.Get("EnableVSyncToolTip"),
@@ -253,6 +191,8 @@ namespace Barotrauma
Selected = VSyncEnabled
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), leftColumn.RectTransform), style: null);
GUITextBlock particleLimitText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("ParticleLimit"));
GUIScrollBar particleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
barSize: 0.1f)
@@ -269,6 +209,8 @@ namespace Barotrauma
};
particleScrollBar.OnMoved(particleScrollBar, particleScrollBar.BarScroll);
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), rightColumn.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("LosEffect"));
var losModeDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform));
losModeDD.AddItem(TextManager.Get("LosModeNone"), LosMode.None);
@@ -287,6 +229,8 @@ namespace Barotrauma
return true;
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), style: null);
GUITextBlock LightText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("LightMapScale"))
{
ToolTip = TextManager.Get("LightMapScaleToolTip")
@@ -307,6 +251,8 @@ namespace Barotrauma
};
lightScrollBar.OnMoved(lightScrollBar, lightScrollBar.BarScroll);
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), style: null);
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("SpecularLighting"))
{
ToolTip = TextManager.Get("SpecularLightingToolTip"),
@@ -319,6 +265,8 @@ namespace Barotrauma
}
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), rightColumn.RectTransform), style: null);
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("ChromaticAberration"))
{
ToolTip = TextManager.Get("ChromaticAberrationToolTip"),
@@ -331,6 +279,9 @@ namespace Barotrauma
}
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), style: null);
GUITextBlock HUDScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("HUDScale"));
GUIScrollBar HUDScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
barSize: 0.1f)
@@ -349,6 +300,9 @@ namespace Barotrauma
};
HUDScaleScrollBar.OnMoved(HUDScaleScrollBar, HUDScaleScrollBar.BarScroll);
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), rightColumn.RectTransform), style: null);
GUITextBlock inventoryScaleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("InventoryScale"));
GUIScrollBar inventoryScaleScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), barSize: 0.1f)
{
@@ -365,6 +319,9 @@ namespace Barotrauma
};
inventoryScaleScrollBar.OnMoved(inventoryScaleScrollBar, inventoryScaleScrollBar.BarScroll);
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), rightColumn.RectTransform), style: null);
/// Audio tab ----------------------------------------------------------------
var audioSliders = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.4f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
@@ -610,10 +567,9 @@ namespace Barotrauma
var inputNames = Enum.GetValues(typeof(InputType));
for (int i = 0; i < inputNames.Length; i++)
{
var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), inputFrame.RectTransform)) { Stretch = true, IsHorizontal = true, RelativeSpacing = 0.05f };
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft) { MinSize = new Point(150, 0) },
TextManager.Get("InputType." + ((InputType)i)) + ": ", font: GUI.SmallFont) { ForceUpperCase = true };
var keyBox = new GUITextBox(new RectTransform(new Vector2(0.7f, 1.0f), inputContainer.RectTransform),
var inputContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), inputFrame.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), inputContainer.RectTransform), TextManager.Get("InputType." + ((InputType)i)) + ": ", font: GUI.SmallFont);
var keyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), inputContainer.RectTransform, Anchor.TopRight),
text: keyMapping[i].ToString(), font: GUI.SmallFont)
{
UserData = i
@@ -637,11 +593,88 @@ namespace Barotrauma
};
aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll);
/// General tab --------------------------------------------------------------
var generalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabs[(int)Tab.General].RectTransform, Anchor.Center)
{ RelativeOffset = new Vector2(0.0f, 0.0f) }) { RelativeSpacing = 0.01f, Stretch = true };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("ContentPackages"));
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), generalLayoutGroup.RectTransform))
{
CanBeFocused = false
};
foreach (ContentPackage contentPackage in ContentPackage.List)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), contentPackageList.Content.RectTransform, minSize: new Point(0, 15)), contentPackage.Name)
{
UserData = contentPackage,
OnSelected = SelectContentPackage,
Selected = SelectedContentPackages.Contains(contentPackage)
};
if (!contentPackage.IsCompatible())
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
tickBox.ToolTip = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
.Replace("[packagename]", contentPackage.Name)
.Replace("[packageversion]", contentPackage.GameVersion.ToString())
.Replace("[gameversion]", GameMain.Version.ToString());
}
else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
{
tickBox.TextColor = Color.Red;
tickBox.Enabled = false;
tickBox.ToolTip = TextManager.Get("ContentPackageMissingCoreFiles")
.Replace("[packagename]", contentPackage.Name)
.Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
}
}
GUITextBlock aimAssistText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), controlsLayoutGroup.RectTransform), TextManager.Get("AimAssist"));
GUIScrollBar aimAssistSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), controlsLayoutGroup.RectTransform),
barSize: 0.1f)
{
UserData = aimAssistText,
BarScroll = MathUtils.InverseLerp(0.0f, 5.0f, AimAssistAmount),
OnMoved = (scrollBar, scroll) =>
{
ChangeSliderText(scrollBar, scroll);
AimAssistAmount = MathHelper.Lerp(0.0f, 5.0f, scroll);
return true;
},
Step = 0.1f
};
aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll);
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("Language"));
var languageDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform));
foreach (string language in TextManager.AvailableLanguages)
{
languageDD.AddItem(TextManager.Get("Language." + language), language);
}
languageDD.SelectItem(TextManager.Language);
languageDD.OnSelected = (guiComponent, obj) =>
{
string newLanguage = obj as string;
if (newLanguage == Language) return true;
UnsavedSettings = true;
Language = newLanguage;
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
return true;
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft),
TextManager.Get("Cancel"), style: "GUIButtonLarge")
TextManager.Get("Cancel"))
{
IgnoreLayoutGroups = true,
OnClicked = (x, y) =>
@@ -657,7 +690,7 @@ namespace Barotrauma
};
applyButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomRight),
TextManager.Get("ApplySettingsButton"), style: "GUIButtonLarge")
TextManager.Get("ApplySettingsButton"))
{
IgnoreLayoutGroups = true,
Enabled = false
@@ -665,7 +698,7 @@ namespace Barotrauma
applyButton.OnClicked = ApplyClicked;
UnsavedSettings = false; // Reset unsaved settings to false once the UI has been created
SelectTab(Tab.Graphics);
SelectTab(Tab.General);
}
private void SelectTab(Tab tab)
@@ -93,7 +93,7 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, bool editing)
{
Color color = item.SpriteColor;
Color color = Color.White;
if (brokenSprite == null)
{
//broken doors turn black if no broken sprite has been configured
@@ -108,7 +108,7 @@ namespace Barotrauma.Items.Components
weldSpritePos.Y = -weldSpritePos.Y;
weldedSprite.Draw(spriteBatch,
weldSpritePos, item.SpriteColor * (stuck / 100.0f), scale: item.Scale);
weldSpritePos, Color.White * (stuck / 100.0f), scale: item.Scale);
}
if (openState == 1.0f)
@@ -175,6 +175,63 @@ namespace Barotrauma.Items.Components
}
}
}
public void ApplyTo(RectTransform target)
{
if (RelativeOffset.HasValue)
{
target.RelativeOffset = RelativeOffset.Value;
}
else if (AbsoluteOffset.HasValue)
{
target.AbsoluteOffset = AbsoluteOffset.Value;
}
if (RelativeSize.HasValue)
{
target.RelativeSize = RelativeSize.Value;
}
else if (AbsoluteSize.HasValue)
{
target.NonScaledSize = AbsoluteSize.Value;
}
if (Anchor.HasValue)
{
target.Anchor = Anchor.Value;
}
if (Pivot.HasValue)
{
target.Pivot = Pivot.Value;
}
else
{
target.Pivot = RectTransform.MatchPivotToAnchor(target.Anchor);
}
target.RecalculateChildren(true, true);
}
}
public GUIFrame GuiFrame { get; protected set; }
[Serialize(false, false)]
public bool AllowUIOverlap
{
get;
set;
}
private ItemComponent linkToUIComponent;
[Serialize("", false)]
public string LinkUIToComponent
{
get;
set;
}
[Serialize(0, false)]
public int HudPriority
{
get;
private set;
}
private bool shouldMuffleLooping;
@@ -496,11 +553,7 @@ namespace Barotrauma.Items.Components
{
msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString());
}
DisplayMsg = msg;
}
else
{
DisplayMsg = Msg;
Msg = msg;
}
}
}
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
{
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
deattachTimer = msg.ReadSingle();
DeattachTimer = msg.ReadSingle();
if (deattachTimer >= DeattachDuration)
{
holdable.DeattachFromWall();
@@ -25,12 +25,6 @@ namespace Barotrauma.Items.Components
DrawHUDBack, null);
submarineContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center), style: null);
new GUICustomComponent(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center),
DrawHUDFront, null)
{
CanBeFocused = false
};
hullInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.13f), GUI.Canvas, minSize: new Point(250, 150)),
style: "InnerFrame")
{
@@ -53,7 +47,7 @@ namespace Barotrauma.Items.Components
public override void AddToGUIUpdateList()
{
base.AddToGUIUpdateList();
hullInfoFrame.AddToGUIUpdateList();
if (hasPower) hullInfoFrame.AddToGUIUpdateList();
}
public override void OnMapLoaded()
@@ -102,27 +96,6 @@ namespace Barotrauma.Items.Components
}
}
private void DrawHUDFront(SpriteBatch spriteBatch, GUICustomComponent container)
{
foreach (GUIComponent child in submarineContainer.Children.First().Children)
{
if (child.UserData is Hull hull)
{
if (hull.Submarine == null || !hull.Submarine.IsOutpost) { continue; }
string text = TextManager.Get("MiniMapOutpostDockingInfo").Replace("[outpost]", hull.Submarine.Name);
Vector2 textSize = GUI.Font.MeasureString(text);
Vector2 textPos = child.Center;
if (textPos.X + textSize.X / 2 > submarineContainer.Rect.Right)
textPos.X -= ((textPos.X + textSize.X / 2) - submarineContainer.Rect.Right) + 10;
if (textPos.X - textSize.X / 2 < submarineContainer.Rect.X)
textPos.X += (submarineContainer.Rect.X - (textPos.X - textSize.X / 2)) + 10;
GUI.DrawString(spriteBatch, textPos - textSize / 2, text,
Color.Orange * (float)Math.Abs(Math.Sin(Timing.TotalTime)), Color.Black * 0.8f);
break;
}
}
}
private void DrawHUDBack(SpriteBatch spriteBatch, GUICustomComponent container)
{
Hull mouseOnHull = null;
@@ -248,7 +221,7 @@ namespace Barotrauma.Items.Components
foreach (Submarine sub in subs)
{
if (sub.HullVertices == null) { continue; }
Rectangle worldBorders = sub.GetDockedBorders();
worldBorders.Location += sub.WorldPosition.ToPoint();
@@ -269,8 +242,6 @@ namespace Barotrauma.Items.Components
GUI.DrawLine(spriteBatch, center + start, center + end, Color.DarkCyan * Rand.Range(0.3f, 0.35f), width: 10);
}
}
}
private void GetLinkedHulls(Hull hull, List<Hull> linkedHulls)
@@ -107,10 +107,7 @@ namespace Barotrauma.Items.Components
{
var warningBtn = new GUIButton(new RectTransform(new Point(buttonWidth, buttonHeight), columnLeft.RectTransform)
{ AbsoluteOffset = new Point((i % buttonsPerRow) * (buttonWidth + spacing), (int)Math.Floor(i / (float)buttonsPerRow) * (buttonHeight + spacing)) },
TextManager.Get(warningTexts[i]), style: "IndicatorButton")
{
CanBeFocused = false
};
TextManager.Get(warningTexts[i]), style: "IndicatorButton");
var btnText = warningBtn.GetChild<GUITextBlock>();
btnText.Font = GUI.SmallFont;
@@ -785,9 +785,8 @@ namespace Barotrauma.Items.Components
foreach (Limb limb in c.AnimController.Limbs)
{
if (!limb.body.Enabled) { continue; }
float pointDist = ((limb.WorldPosition - pingSource) * displayScale).LengthSquared();
if (limb.SimPosition == Vector2.Zero || pointDist > DisplayRadius * DisplayRadius) continue;
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
@@ -484,14 +484,26 @@ namespace Barotrauma.Items.Components
user = Character.Controlled;
}
}
if (!AutoPilot && Character.DisableControls && GUI.KeyboardDispatcher.Subscriber == null)
if (!AutoPilot && Character.DisableControls)
{
steeringAdjustSpeed = character == null ? 0.2f : MathHelper.Lerp(0.2f, 1.0f, character.GetSkillLevel("helm") / 100.0f);
Vector2 input = Vector2.Zero;
if (PlayerInput.KeyDown(InputType.Left)) { input -= Vector2.UnitX; }
if (PlayerInput.KeyDown(InputType.Right)) { input += Vector2.UnitX; }
if (PlayerInput.KeyDown(InputType.Up)) { input += Vector2.UnitY; }
if (PlayerInput.KeyDown(InputType.Down)) { input -= Vector2.UnitY; }
if (PlayerInput.KeyDown(InputType.Left))
{
input -= Vector2.UnitX;
}
if (PlayerInput.KeyDown(InputType.Right))
{
input += Vector2.UnitX;
}
if (PlayerInput.KeyDown(InputType.Up))
{
input += Vector2.UnitY;
}
if (PlayerInput.KeyDown(InputType.Down))
{
input -= Vector2.UnitY;
}
if (PlayerInput.KeyDown(Keys.LeftShift))
{
SteeringInput += input * deltaTime * 200;
@@ -1,7 +1,6 @@
using Barotrauma.Particles;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,21 +11,12 @@ using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class RepairTool
#if DEBUG
: IDrawableComponent
#endif
{
public ParticleEmitter ParticleEmitter
{
get;
private set;
}
#if DEBUG
public Vector2 DrawSize
{
get { return GameMain.DebugDraw ? Vector2.One * Range : Vector2.Zero; }
}
#endif
private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>();
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
@@ -132,17 +122,5 @@ namespace Barotrauma.Items.Components
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
}
#if DEBUG
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (GameMain.DebugDraw && IsActive)
{
GUI.DrawLine(spriteBatch,
new Vector2(debugRayStartPos.X, -debugRayStartPos.Y),
new Vector2(debugRayEndPos.X, -debugRayEndPos.Y),
Color.Yellow);
}
}
#endif
}
}
@@ -1,6 +1,4 @@
using Barotrauma.Networking;
using Barotrauma.Particles;
using Lidgren.Network;
using Barotrauma.Particles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
@@ -114,7 +112,8 @@ namespace Barotrauma.Items.Components
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
{
if (!(c.UserData is Skill skill)) continue;
Skill skill = c.UserData as Skill;
if (skill == null) continue;
GUITextBlock textBlock = (GUITextBlock)c;
if (character.GetSkillLevel(skill.Identifier) < skill.Level)
@@ -127,15 +126,5 @@ namespace Barotrauma.Items.Components
}
}
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
deteriorationTimer = msg.ReadSingle();
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
//no need to write anything, just letting the server know we started repairing
}
}
}
@@ -169,6 +169,20 @@ namespace Barotrauma.Items.Components
if (draggingConnected.Connect(this, !alreadyConnected, true))
{
var otherConnection = draggingConnected.OtherConnection(this);
#if SERVER
//TODO: ffs
if (otherConnection == null)
{
GameServer.Log(Character.Controlled.LogName + " connected a wire to " +
Item.Name + " (" + Name + ")", ServerLog.MessageType.ItemInteraction);
}
else
{
GameServer.Log(Character.Controlled.LogName + " connected a wire from " +
Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction);
}
#endif
SetWire(index, draggingConnected);
}
}
@@ -181,7 +181,7 @@ namespace Barotrauma.Items.Components
Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths = new Dictionary<AfflictionPrefab, float>();
foreach (Affliction affliction in allAfflictions)
{
if (affliction.Strength < affliction.Prefab.ShowInHealthScannerThreshold || affliction.Strength <= 0.0f) continue;
if (affliction.Strength < affliction.Prefab.ActivationThreshold || affliction.Strength <= 0.0f) continue;
if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
{
combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
@@ -237,13 +237,13 @@ namespace Barotrauma.Items.Components
railSprite?.Draw(spriteBatch,
drawPos,
item.SpriteColor,
Color.White,
rotation + MathHelper.PiOver2, item.Scale,
SpriteEffects.None, item.SpriteDepth + (railSprite.Depth - item.Sprite.Depth));
barrelSprite?.Draw(spriteBatch,
drawPos - new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * recoilOffset * item.Scale,
item.SpriteColor,
drawPos - new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * recoilOffset * item.Scale,
Color.White,
rotation + MathHelper.PiOver2, item.Scale,
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
@@ -301,7 +301,7 @@ namespace Barotrauma
protected virtual void ControlInput(Camera cam)
{
// Note that these targets are static. Therefore the outcome is the same if this method is called multiple times or only once.
if (selectedSlot != null && !DraggingItemToWorld)
if (selectedSlot != null || draggingItem != null)
{
cam.Freeze = true;
}
@@ -609,17 +609,8 @@ namespace Barotrauma
if (selectedSlot == null)
{
if (DraggingItemToWorld &&
Character.Controlled.FocusedItem?.OwnInventory != null &&
Character.Controlled.FocusedItem.OwnInventory.TryPutItem(draggingItem, Character.Controlled))
{
GUI.PlayUISound(GUISoundType.PickItem);
}
else
{
GUI.PlayUISound(GUISoundType.DropItem);
draggingItem.Drop(Character.Controlled);
}
draggingItem.Drop(Character.Controlled);
GUI.PlayUISound(GUISoundType.DropItem);
}
else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem)
{
@@ -711,27 +702,10 @@ namespace Barotrauma
int iconSize = (int)(64 * GUI.Scale);
float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f);
Vector2 itemPos = PlayerInput.MousePosition;
if (GUI.MouseOn == null && selectedSlot == null)
{
var shadowSprite = GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0];
string toolTip = Character.Controlled.FocusedItem != null ?
TextManager.Get("PutItemIn").Replace("[itemname]", Character.Controlled.FocusedItem.Name) :
TextManager.Get("DropItem");
int textWidth = (int)Math.Max(GUI.Font.MeasureString(draggingItem.Name).X, GUI.SmallFont.MeasureString(toolTip).X);
int textSpacing = (int)(15 * GUI.Scale);
Point shadowBorders = (new Point(40, 10)).Multiply(GUI.Scale);
shadowSprite.Draw(spriteBatch,
new Rectangle(itemPos.ToPoint() - new Point(iconSize / 2) - shadowBorders, new Point(iconSize + textWidth + textSpacing, iconSize) + shadowBorders.Multiply(2)), Color.Black * 0.8f);
GUI.DrawString(spriteBatch, new Vector2(itemPos.X + iconSize / 2 + textSpacing, itemPos.Y - iconSize / 2), draggingItem.Name, Color.White);
GUI.DrawString(spriteBatch, new Vector2(itemPos.X + iconSize / 2 + textSpacing, itemPos.Y), toolTip,
color: Character.Controlled.FocusedItem == null ? Color.Red : Color.LightGreen,
font: GUI.SmallFont);
}
sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black, scale: scale);
sprite.Draw(spriteBatch,
itemPos,
sprite == draggingItem.Sprite ? draggingItem.GetSpriteColor() : draggingItem.GetInventoryIconColor(),
sprite.Draw(spriteBatch,
itemPos,
sprite == draggingItem.Sprite ? draggingItem.GetSpriteColor() : draggingItem.GetInventoryIconColor(),
scale: scale);
}
}
@@ -10,6 +10,12 @@ namespace Barotrauma
protected override void ControlInput(Camera cam)
{
if (draggingItem == null && HUD.CloseHUD(BackgroundFrame))
{
// TODO: fix so that works with the server side
Character.Controlled.SelectedConstruction = null;
return;
}
base.ControlInput(cam);
if (BackgroundFrame.Contains(PlayerInput.MousePosition))
{
@@ -232,11 +232,11 @@ namespace Barotrauma
{
if (!ResizeHorizontal && !ResizeVertical)
{
sprite.Draw(spriteBatch, new Vector2(placeRect.Center.X, -(placeRect.Y - placeRect.Height / 2)), SpriteColor * 0.8f, scale: Scale * scale);
sprite.Draw(spriteBatch, new Vector2(placeRect.Center.X, -(placeRect.Y - placeRect.Height / 2)), SpriteColor, scale: Scale * scale);
}
else
{
if (sprite != null) sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), placeRect.Size.ToVector2(), null, SpriteColor * 0.8f);
if (sprite != null) sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), placeRect.Size.ToVector2(), null, SpriteColor);
}
}
}
+41 -11
View File
@@ -1,13 +1,14 @@
using Barotrauma.Networking;
using Barotrauma.Particles;
using Barotrauma.Sounds;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;
using System.Linq;
using Lidgren.Network;
namespace Barotrauma
{
@@ -18,8 +19,6 @@ namespace Barotrauma
private List<Decal> decals = new List<Decal>();
private float serverUpdateDelay;
private float remoteWaterVolume, remoteOxygenPercentage;
private List<Vector3> remoteFireSources;
private bool networkUpdatePending;
private float networkUpdateTimer;
@@ -140,10 +139,6 @@ namespace Barotrauma
partial void UpdateProjSpecific(float deltaTime, Camera cam)
{
serverUpdateDelay -= deltaTime;
if (serverUpdateDelay <= 0.0f)
{
ApplyRemoteState();
}
if (networkUpdatePending)
{
@@ -552,18 +547,18 @@ namespace Barotrauma
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
{
remoteWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
remoteOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
float newWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
float newOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
bool hasFireSources = message.ReadBoolean();
int fireSourceCount = 0;
remoteFireSources = new List<Vector3>();
List<Vector3> newFireSources = new List<Vector3>();
if (hasFireSources)
{
fireSourceCount = message.ReadRangedInteger(0, 16);
for (int i = 0; i < fireSourceCount; i++)
{
remoteFireSources.Add(new Vector3(
newFireSources.Add(new Vector3(
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
message.ReadRangedSingle(0.0f, 1.0f, 8)));
@@ -572,6 +567,41 @@ namespace Barotrauma
if (serverUpdateDelay > 0.0f) { return; }
WaterVolume = newWaterVolume;
OxygenPercentage = newOxygenPercentage;
for (int i = 0; i < fireSourceCount; i++)
{
Vector2 pos = new Vector2(
rect.X + rect.Width * newFireSources[i].X,
rect.Y - rect.Height + (rect.Height * newFireSources[i].Y));
float size = newFireSources[i].Z * rect.Width;
var newFire = i < FireSources.Count ?
FireSources[i] :
new FireSource(Submarine == null ? pos : pos + Submarine.Position, null, true);
newFire.Position = pos;
newFire.Size = new Vector2(size, newFire.Size.Y);
//ignore if the fire wasn't added to this room (invalid position)?
if (!FireSources.Contains(newFire))
{
newFire.Remove();
continue;
}
}
for (int i = FireSources.Count - 1; i >= fireSourceCount; i--)
{
FireSources[i].Remove();
if (i < FireSources.Count)
{
FireSources.RemoveAt(i);
}
}
if (serverUpdateDelay > 0.0f) { return; }
ApplyRemoteState();
}
@@ -247,11 +247,15 @@ namespace Barotrauma.Lights
public void Rotate(Vector2 origin, float amount)
{
Matrix rotationMatrix =
Matrix.CreateTranslation(-origin.X, -origin.Y, 0.0f) *
Matrix.CreateRotationZ(amount) *
Matrix.CreateTranslation(origin.X, origin.Y, 0.0f);
SetVertices(vertices.Select(v => v.Pos).ToArray(), rotationMatrix);
Matrix rotationMatrix = Matrix.CreateRotationZ(amount);
Vector2[] newVerts = new Vector2[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
newVerts[i] = Vector2.Transform(vertices[i].Pos - origin, rotationMatrix) + origin;
}
SetVertices(newVerts);
}
private void CalculateDimensions()
@@ -453,10 +453,7 @@ namespace Barotrauma.Lights
//raster pattern on top of everything
spriteBatch.Begin(blendState: BlendState.AlphaBlend, samplerState: SamplerState.LinearWrap);
spriteBatch.Draw(highlightRaster,
new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height),
new Rectangle(0, 0, (int)(HighlightMap.Width / currLightMapScale * 0.5f), (int)(HighlightMap.Height / currLightMapScale * 0.5f)),
Color.White * 0.5f);
spriteBatch.Draw(highlightRaster, new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height), new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height), Color.White * 0.5f);
spriteBatch.End();
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
@@ -364,23 +364,15 @@ namespace Barotrauma
}
}
if (GUI.KeyboardDispatcher.Subscriber == null)
{
float moveSpeed = 1000.0f;
Vector2 moveAmount = Vector2.Zero;
if (PlayerInput.KeyDown(InputType.Left)) { moveAmount += Vector2.UnitX; }
if (PlayerInput.KeyDown(InputType.Right)) { moveAmount -= Vector2.UnitX; }
if (PlayerInput.KeyDown(InputType.Up)) { moveAmount += Vector2.UnitY; }
if (PlayerInput.KeyDown(InputType.Down)) { moveAmount -= Vector2.UnitY; }
drawOffset += moveAmount * moveSpeed / zoom * deltaTime;
}
if (GUI.MouseOn == mapContainer)
{
zoom += PlayerInput.ScrollWheelSpeed / 1000.0f;
zoom = MathHelper.Clamp(zoom, 1.0f, 4.0f);
if (PlayerInput.MidButtonHeld()) { drawOffset += PlayerInput.MouseSpeed / zoom; }
if (PlayerInput.MidButtonHeld())
{
drawOffset += PlayerInput.MouseSpeed / zoom;
}
#if DEBUG
if (PlayerInput.DoubleClicked() && highlightedLocation != null)
{
@@ -559,6 +551,11 @@ namespace Barotrauma
null, connectionColor * MathHelper.Clamp(a, 0.1f, 0.5f), MathUtils.VectorToAngle(end - start),
new Vector2(0, 16), SpriteEffects.None, 0.01f);
}
}
rect.Inflate(8, 8);
GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8);
GUI.DrawRectangle(spriteBatch, rect, Color.LightGray);
if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames)
{
@@ -44,7 +44,7 @@ namespace Barotrauma
drawRect.Location -= Submarine.MainSub.Position.ToPoint();
}
drawRect.Y = -drawRect.Y;
GUI.DrawRectangle(spriteBatch, drawRect, Color.White);
GUI.DrawRectangle(spriteBatch, drawRect, Color.DarkBlue);
}
public void DrawListLine(SpriteBatch spriteBatch, Vector2 pos, Color color)
{
@@ -75,10 +75,7 @@ namespace Barotrauma
};
var h = new ConvexHull(verts, Color.Black, this);
if (Math.Abs(rotation) > 0.001f)
{
h.Rotate(position, rotation);
}
h.Rotate(position, rotation);
convexHulls.Add(h);
}
@@ -295,7 +292,8 @@ namespace Barotrauma
{
if (damageEffect != null)
{
float newCutoff = MathHelper.Lerp(0.0f, 0.65f, Sections[i].damage / Prefab.Health);
float newCutoff = Sections[i].damage > 0 ?
MathHelper.Lerp(0.2f, 0.65f, Sections[i].damage / Prefab.Health) : 0.0f;
if (Math.Abs(newCutoff - Submarine.DamageEffectCutoff) > 0.01f || color != Submarine.DamageEffectColor)
{
@@ -362,7 +360,6 @@ namespace Barotrauma
-Bodies[i].Rotation, Color.White);
}
}
AiTarget?.Draw(spriteBatch);
}
}
@@ -35,7 +35,7 @@ namespace Barotrauma
public override void DrawPlacing(SpriteBatch spriteBatch, Rectangle placeRect, float scale = 1.0f)
{
// TODO: the scale property is not used
sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), new Vector2(placeRect.Width, placeRect.Height), color: Color.White * 0.8f, textureScale: TextureScale * Scale);
sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), new Vector2(placeRect.Width, placeRect.Height), textureScale: TextureScale * Scale);
}
}
}
@@ -141,23 +141,8 @@ namespace Barotrauma.Networking
{
OnClicked = (btn, userdata) =>
{
if (!permissions.HasFlag(ClientPermissions.ManageRound)) { return false; }
if (!Submarine.MainSub.AtStartPosition && !Submarine.MainSub.AtEndPosition)
{
var msgBox = new GUIMessageBox("", TextManager.Get("EndRoundSubNotAtLevelEnd"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = (_, __) =>
{
GameMain.Client.RequestRoundEnd();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
}
else
{
RequestRoundEnd();
}
if (!permissions.HasFlag(ClientPermissions.ManageRound)) return false;
RequestRoundEnd();
return true;
},
Visible = false
@@ -637,7 +622,7 @@ namespace Barotrauma.Networking
if (gameStarted) SetRadioButtonColor();
if (ShowNetStats && client?.ServerConnection != null)
if (ShowNetStats)
{
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, client.ServerConnection.Statistics.ReceivedBytes);
netStats.AddValue(NetStats.NetStatType.SentBytes, client.ServerConnection.Statistics.SentBytes);
@@ -1124,7 +1109,7 @@ namespace Barotrauma.Networking
{
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed " + Level.Loaded.Seed + ").";
DebugConsole.ThrowError(errorMsg, createMessageBox: true);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + levelSeed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch"+levelSeed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
CoroutineManager.StartCoroutine(EndGame(""));
yield return CoroutineStatus.Failure;
}
@@ -1396,6 +1381,9 @@ namespace Barotrauma.Networking
case ServerNetObject.CLIENT_LIST:
ReadClientList(inc);
break;
case ServerNetObject.CLIENT_LIST:
ReadClientList(inc);
break;
case ServerNetObject.CHAT_MESSAGE:
ChatMessage.ClientRead(inc);
break;
@@ -1451,11 +1439,7 @@ namespace Barotrauma.Networking
break;
case ServerNetObject.ENTITY_EVENT:
case ServerNetObject.ENTITY_EVENT_INITIAL:
if (!entityEventManager.Read(objHeader, inc, sendingTime, entities))
{
eventReadFailed = true;
break;
}
if (!entityEventManager.Read(objHeader, inc, sendingTime, entities)) { break; }
break;
case ServerNetObject.CHAT_MESSAGE:
ChatMessage.ClientRead(inc);
@@ -1719,8 +1703,6 @@ namespace Barotrauma.Networking
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
campaign.LastSaveID = campaign.PendingSaveID;
DebugConsole.Log("Campaign save received, save ID " + campaign.LastSaveID);
//decrement campaign update ID so the server will send us the latest data
//(as there may have been campaign updates after the save file was created)
campaign.LastUpdateID--;
@@ -1738,7 +1720,7 @@ namespace Barotrauma.Networking
public override void CreateEntityEvent(INetSerializable entity, object[] extraData)
{
if (!(entity is IClientSerializable)) throw new InvalidCastException("Entity is not IClientSerializable");
if (!(entity is IClientSerializable)) throw new InvalidCastException("entity is not IClientSerializable");
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
}
@@ -2007,8 +1989,7 @@ namespace Barotrauma.Networking
msg.Write(true); msg.WritePadBits();
msg.Write(savePath);
msg.Write(mapSeed);
msg.Write(sub.Name);
msg.Write(sub.MD5Hash.Hash);
msg.Write(sub.FilePath);
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
@@ -62,7 +62,7 @@ namespace Barotrauma
UpdateSubList(submarines);
// New game right sideon
// New game right side
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), TextManager.Get("SaveName") + ":", textAlignment: Alignment.BottomLeft);
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), string.Empty);
@@ -262,6 +262,11 @@ namespace Barotrauma
saveFiles = SaveUtil.GetSaveFiles(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer);
}
saveList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), loadGameContainer.RectTransform, Anchor.CenterLeft))
{
OnSelected = SelectSaveFile
};
saveList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), loadGameContainer.RectTransform, Anchor.CenterLeft))
{
OnSelected = SelectSaveFile
@@ -269,9 +274,7 @@ namespace Barotrauma
foreach (string saveFile in saveFiles)
{
string fileName = saveFile;
string subName = "";
string saveTime = "";
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFile);
var saveFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), saveList.Content.RectTransform), style: "ListBoxElement")
{
UserData = saveFile
@@ -279,38 +282,25 @@ namespace Barotrauma
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform),
text: Path.GetFileNameWithoutExtension(saveFile));
if (doc?.Root == null)
{
DebugConsole.ThrowError("Error loading save file \"" + saveFile + "\". The file may be corrupted.");
nameText.Color = Color.Red;
continue;
}
if (!isMultiplayer)
{
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFile);
if (doc?.Root == null)
{
DebugConsole.ThrowError("Error loading save file \"" + saveFile + "\". The file may be corrupted.");
nameText.Color = Color.Red;
continue;
}
subName = doc.Root.GetAttributeString("submarine", "");
saveTime = doc.Root.GetAttributeString("savetime", "");
}
else
{
string[] splitSaveFile = saveFile.Split(';');
saveFrame.UserData = splitSaveFile[0];
fileName = nameText.Text = Path.GetFileNameWithoutExtension(splitSaveFile[0]);
if (splitSaveFile.Length > 1) { subName = splitSaveFile[1]; }
if (splitSaveFile.Length > 2) { saveTime = splitSaveFile[2]; }
}
string submarineName = doc.Root.GetAttributeString("submarine", "");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform, Anchor.BottomLeft),
text: subName, font: GUI.SmallFont)
text: submarineName, font: GUI.SmallFont)
{
UserData = fileName
UserData = saveFile
};
string saveTime = doc.Root.GetAttributeString("savetime", "");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), saveFrame.RectTransform),
text: saveTime, textAlignment: Alignment.Right, font: GUI.SmallFont)
{
UserData = fileName
UserData = saveFile
};
}
@@ -355,6 +345,13 @@ namespace Barotrauma
};
}
public void UpdateTutorialSelection()
{
if (isMultiplayer) return;
Tutorial contextualTutorial = Tutorial.Tutorials.Find(t => t is ContextualTutorial);
contextualTutorialBox.Selected = (contextualTutorial != null) ? !GameMain.Config.CompletedTutorialNames.Contains(contextualTutorial.Name) : true;
}
public void UpdateTutorialSelection()
{
if (isMultiplayer) return;
@@ -457,14 +457,11 @@ namespace Barotrauma
{
IgnoreLayoutGroups = true,
OnClicked = (GUIButton btn, object obj) => { StartRound?.Invoke(); return true; },
Enabled = true
Enabled = true,
Visible = GameMain.Client == null ||
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign)
};
if (GameMain.Client != null)
{
startButton.Visible = !GameMain.Client.GameStarted &&
(GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
}
}
OnLocationSelected?.Invoke(location, connection);
@@ -118,19 +118,6 @@ namespace Barotrauma
instance = this;
}
private void Reset()
{
AnimParams.ForEach(a => a.Reset(true));
RagdollParams.Reset(true);
RagdollParams.ClearHistory();
CurrentAnimation.ClearHistory();
if (!character.Removed)
{
character.Remove();
}
character = null;
}
public override void Deselect()
{
base.Deselect();
@@ -141,7 +128,15 @@ namespace Barotrauma
isEndlessRunner = false;
if (character != null)
{
Reset();
AnimParams.ForEach(a => a.Reset(true));
RagdollParams.Reset(true);
RagdollParams.ClearHistory();
CurrentAnimation.ClearHistory();
if (!character.Removed)
{
character.Remove();
}
character = null;
}
GameMain.World.ProcessChanges();
}
@@ -398,12 +393,6 @@ namespace Barotrauma
}
if (!isFreezed)
{
if (character.AnimController.Invalid)
{
Reset();
SpawnCharacter(currentCharacterConfig);
}
Submarine.MainSub.SetPrevTransform(Submarine.MainSub.Position);
Submarine.MainSub.Update((float)deltaTime);
@@ -1226,7 +1215,7 @@ namespace Barotrauma
Cam.Position = character.WorldPosition;
}
private bool CreateCharacter(string name, string mainFolder, bool isHumanoid, params object[] ragdollConfig)
private bool CreateCharacter(string name, bool isHumanoid, params object[] ragdollConfig)
{
var contentPackage = GameMain.Config.SelectedContentPackages.LastOrDefault();
if (contentPackage == null)
@@ -1239,22 +1228,23 @@ namespace Barotrauma
#if !DEBUG
if (vanilla != null && contentPackage == vanilla)
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), Color.Red, font: GUI.LargeFont);
GUI.AddMessage($"Cannot edit the Vanilla content!", Color.Red, font: GUI.LargeFont);
return false;
}
#endif
string speciesName = name;
string mainFolder = $"Content/Characters/{speciesName}";
// Config file
string configFilePath = Path.Combine(mainFolder, $"{speciesName}.xml").Replace(@"\", @"/");
string configFilePath = $"{mainFolder}/{speciesName}.xml";
if (ContentPackage.GetFilesOfType(GameMain.SelectedPackages, ContentType.Character).None(path => path.Contains(speciesName)))
{
// Create the config file
XElement mainElement = new XElement("Character",
new XAttribute("name", speciesName),
new XAttribute("humanoid", isHumanoid),
new XElement("ragdolls", new XAttribute("folder", Path.Combine(mainFolder, $"Ragdolls/").Replace(@"\", @"/"))),
new XElement("animations", new XAttribute("folder", Path.Combine(mainFolder, $"Animations/").Replace(@"\", @"/"))),
new XElement("ragdolls"),
new XElement("animations"),
new XElement("health"),
new XElement("ai"));
XDocument doc = new XDocument(mainElement);
@@ -1269,13 +1259,13 @@ namespace Barotrauma
DebugConsole.NewMessage(GetCharacterEditorTranslation("ContentPackageSaved").Replace("[path]", contentPackage.Path));
}
// Ragdoll
string ragdollFolder = RagdollParams.GetFolder(speciesName);
string ragdollFolder = RagdollParams.GetDefaultFolder(speciesName);
string ragdollPath = RagdollParams.GetDefaultFile(speciesName);
RagdollParams ragdollParams = isHumanoid
? RagdollParams.CreateDefault<HumanRagdollParams>(ragdollPath, speciesName, ragdollConfig)
: RagdollParams.CreateDefault<FishRagdollParams>(ragdollPath, speciesName, ragdollConfig) as RagdollParams;
// Animations
string animFolder = AnimationParams.GetFolder(speciesName);
string animFolder = AnimationParams.GetDefaultFolder(speciesName);
foreach (AnimationType animType in Enum.GetValues(typeof(AnimationType)))
{
if (animType != AnimationType.NotDefined)
@@ -1879,7 +1869,7 @@ namespace Barotrauma
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(currentCharacterConfig))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), Color.Red, font: GUI.LargeFont);
GUI.AddMessage(GetCharacterEditorTranslation("CantEditVanillaContent"), Color.Red, font: GUI.LargeFont);
return false;
}
#endif
@@ -1894,7 +1884,7 @@ namespace Barotrauma
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(currentCharacterConfig))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), Color.Red, font: GUI.LargeFont);
GUI.AddMessage(GetCharacterEditorTranslation("CantEditVanillaContent"), Color.Red, font: GUI.LargeFont);
return false;
}
#endif
@@ -1966,7 +1956,7 @@ namespace Barotrauma
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(currentCharacterConfig))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), Color.Red, font: GUI.LargeFont);
GUI.AddMessage(GetCharacterEditorTranslation("CantEditVanillaContent"), Color.Red, font: GUI.LargeFont);
box.Close();
return false;
}
@@ -2099,7 +2089,7 @@ namespace Barotrauma
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(currentCharacterConfig))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), Color.Red, font: GUI.LargeFont);
GUI.AddMessage(GetCharacterEditorTranslation("CantEditVanillaContent"), Color.Red, font: GUI.LargeFont);
box.Close();
return false;
}
@@ -3928,7 +3918,7 @@ namespace Barotrauma
private void DrawJointLimitWidgets(SpriteBatch spriteBatch, Limb limb, LimbJoint joint, Vector2 drawPos, bool autoFreeze, bool allowPairEditing, float rotationOffset = 0)
{
rotationOffset += MathHelper.ToRadians(RagdollParams.SpritesheetOrientation);
rotationOffset -= MathHelper.ToRadians(RagdollParams.SpritesheetOrientation);
Color angleColor = joint.UpperLimit - joint.LowerLimit > 0 ? Color.LightGreen * 0.5f : Color.Red;
DrawRadialWidget(spriteBatch, drawPos, MathHelper.ToDegrees(joint.UpperLimit), $"joint.jointParams.Name {GetCharacterEditorTranslation("UpperLimit")}", Color.Cyan, angle =>
{
@@ -4662,7 +4652,7 @@ namespace Barotrauma
LimbXElements.Values,
JointXElements
};
if (CharacterEditorScreen.instance.CreateCharacter(Name, Path.GetDirectoryName(XMLPath), IsHumanoid, ragdollParams))
if (CharacterEditorScreen.instance.CreateCharacter(Name, IsHumanoid, ragdollParams))
{
GUI.AddMessage(GetCharacterEditorTranslation("CharacterCreated").Replace("[name]", Name), Color.Green, font: GUI.Font);
}
@@ -51,7 +51,7 @@ namespace Barotrauma
new GUIImage(new RectTransform(new Vector2(0.35f, 0.2f), Frame.RectTransform, Anchor.BottomRight) { RelativeOffset = new Vector2(0.05f, 0.05f) },
style: "TitleText");
buttonsParent = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.85f), parent: Frame.RectTransform, anchor: Anchor.BottomLeft, pivot: Pivot.BottomLeft)
buttonsParent = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.85f), parent: Frame.RectTransform, anchor: Anchor.BottomLeft, pivot: Pivot.BottomLeft)
{
AbsoluteOffset = new Point(50, 0)
})
@@ -61,7 +61,7 @@ namespace Barotrauma
};
// === CAMPAIGN
var campaignHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, isHorizontal: true);
var campaignHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, isHorizontal: true);
new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), campaignHolder.RectTransform), "MainMenuCampaignIcon")
{
@@ -107,7 +107,7 @@ namespace Barotrauma
};
// === MULTIPLAYER
var multiplayerHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.0f) }, isHorizontal: true);
var multiplayerHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.0f) }, isHorizontal: true);
new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), multiplayerHolder.RectTransform), "MainMenuMultiplayerIcon")
{
@@ -152,7 +152,7 @@ namespace Barotrauma
};
// === CUSTOMIZE
var customizeHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.15f, 0.0f) }, isHorizontal: true);
var customizeHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.15f, 0.0f) }, isHorizontal: true);
new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), customizeHolder.RectTransform), "MainMenuCustomizeIcon")
{
@@ -209,7 +209,7 @@ namespace Barotrauma
}
// === OPTION
var optionHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.5f), parent: buttonsParent.RectTransform), isHorizontal: true);
var optionHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.5f), parent: buttonsParent.RectTransform), isHorizontal: true);
new GUIImage(new RectTransform(new Vector2(0.15f, 0.6f), optionHolder.RectTransform), "MainMenuOptionIcon")
{
@@ -219,7 +219,7 @@ namespace Barotrauma
//spacing
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.0f), optionHolder.RectTransform), style: null);
var optionButtons = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1.0f), parent: optionHolder.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.15f) });
var optionButtons = new GUILayoutGroup(new RectTransform(new Vector2(0.55f, 1.0f), parent: optionHolder.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.15f) });
var optionList = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.15f), parent: optionButtons.RectTransform))
{
@@ -241,7 +241,7 @@ namespace Barotrauma
//debug button for quickly starting a new round
#if DEBUG
new GUIButton(new RectTransform(new Vector2(0.8f, 0.1f), buttonsParent.RectTransform, Anchor.TopLeft, Pivot.BottomLeft) { AbsoluteOffset = new Point(0, -40) },
new GUIButton(new RectTransform(new Vector2(0.5f, 0.1f), buttonsParent.RectTransform, Anchor.TopLeft, Pivot.BottomLeft) { AbsoluteOffset = new Point(0, -40) },
"Quickstart (dev)", style: "GUIButtonLarge", color: Color.Red)
{
IgnoreLayoutGroups = true,
@@ -255,7 +255,7 @@ namespace Barotrauma
#endif
var minButtonSize = new Point(120, 20);
var maxButtonSize = new Point(480, 80);
var maxButtonSize = new Point(240, 40);
/*new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("TutorialButton"), style: "GUIButtonLarge")
{
@@ -270,21 +270,16 @@ namespace Barotrauma
SetupButtons(buttons);
buttons.ForEach(b => b.TextBlock.SetTextPos());*/
var relativeSize = new Vector2(0.6f, 0.5f);
var relativeSize = new Vector2(0.5f, 0.5f);
var minSize = new Point(600, 400);
var maxSize = new Point(2000, 1500);
var anchor = Anchor.CenterRight;
var pivot = Pivot.CenterRight;
Vector2 relativeSpacing = new Vector2(0.05f, 0.0f);
var maxSize = new Point(900, 600);
var anchor = Anchor.Center;
var pivot = Pivot.Center;
menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length + 1];
menuTabs[(int)Tab.Settings] = new GUIFrame(new RectTransform(new Vector2(relativeSize.X, 0.8f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing },
style: null);
menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize));
var paddedNewGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.NewGame].RectTransform, Anchor.Center), style: null);
menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize));
var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center), style: null);
campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame, Submarine.SavedSubmarines)
@@ -295,13 +290,13 @@ namespace Barotrauma
var hostServerScale = new Vector2(0.7f, 1.0f);
menuTabs[(int)Tab.HostServer] = new GUIFrame(new RectTransform(
Vector2.Multiply(relativeSize, hostServerScale), GUI.Canvas, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale)) { RelativeOffset = relativeSpacing });
Vector2.Multiply(relativeSize, hostServerScale), GUI.Canvas, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale)));
CreateHostServerFields();
//----------------------------------------------------------------------
menuTabs[(int)Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[(int)Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize));
//PLACEHOLDER
var tutorialList = new GUIListBox(
@@ -382,7 +377,6 @@ namespace Barotrauma
return false;
}
GameMain.Config.ResetSettingsFrame();
selectedTab = (Tab)obj;
switch (selectedTab)
@@ -395,9 +389,8 @@ namespace Barotrauma
campaignSetupUI.UpdateLoadMenu();
break;
case Tab.Settings:
menuTabs[(int)Tab.Settings].RectTransform.ClearChildren();
GameMain.Config.SettingsFrame.RectTransform.Parent = menuTabs[(int)Tab.Settings].RectTransform;
GameMain.Config.SettingsFrame.RectTransform.RelativeSize = Vector2.One;
GameMain.Config.ResetSettingsFrame();
menuTabs[(int)Tab.Settings] = GameMain.Config.SettingsFrame;
break;
case Tab.JoinServer:
GameMain.ServerListScreen.Select();
@@ -233,8 +233,7 @@ namespace Barotrauma
levelSeed = value;
int intSeed = ToolBox.StringToInt(levelSeed);
backgroundSprite = LocationType.Random(new MTRandom(intSeed))?.GetPortrait(intSeed);
backgroundSprite = LocationType.Random(levelSeed)?.GetPortrait(ToolBox.StringToInt(levelSeed));
seedBox.Text = levelSeed;
//lastUpdateID++;
@@ -727,12 +726,6 @@ namespace Barotrauma
spectateButton.Visible = GameMain.Client.GameStarted;
ReadyToStartBox.Visible = !GameMain.Client.GameStarted;
ReadyToStartBox.Selected = false;
if (campaignUI?.StartButton != null)
{
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign));
}
GameMain.Client.SetReadyToStart(ReadyToStartBox);
}
else
@@ -854,9 +847,9 @@ namespace Barotrauma
if (campaignUI?.StartButton != null)
{
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign));
campaignUI.StartButton.Visible =
GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign);
}
}
@@ -867,21 +860,18 @@ namespace Barotrauma
spectateButton.Enabled = true;
}
public void SetCampaignCharacterInfo(CharacterInfo newCampaignCharacterInfo)
{
if (newCampaignCharacterInfo != null)
public void SetCampaignCharacterInfo(CharacterInfo characterInfo)
{
if (CampaignCharacterDiscarded) return;
campaignCharacterInfo = characterInfo;
if (campaignCharacterInfo != null)
{
if (CampaignCharacterDiscarded) { return; }
if (campaignCharacterInfo != newCampaignCharacterInfo)
{
campaignCharacterInfo = newCampaignCharacterInfo;
UpdatePlayerFrame(campaignCharacterInfo, false);
}
UpdatePlayerFrame(campaignCharacterInfo, false);
}
else if (campaignCharacterInfo != null)
else
{
campaignCharacterInfo = null;
UpdatePlayerFrame(campaignCharacterInfo, false);
UpdatePlayerFrame(null, true);
}
}
@@ -337,24 +337,7 @@ namespace Barotrauma
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.03f), paddedLeftPanel.RectTransform), TextManager.Get("ShowLighting"))
{
Selected = lightingEnabled,
OnSelected = (GUITickBox obj) =>
{
lightingEnabled = obj.Selected;
if (lightingEnabled)
{
//turn off lights that are inside containers
foreach (Item item in Item.ItemList)
{
foreach (LightComponent lightComponent in item.GetComponents<LightComponent>())
{
lightComponent.Light.Color = item.Container != null || (item.body != null && !item.body.Enabled) ?
Color.Transparent :
lightComponent.LightColor;
}
}
}
return true;
}
OnSelected = (GUITickBox obj) => { lightingEnabled = obj.Selected; return true; }
};
tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.03f), paddedLeftPanel.RectTransform), TextManager.Get("ShowWalls"))
{
@@ -581,9 +564,6 @@ namespace Barotrauma
MapEntityPrefab.Selected = null;
saveFrame = null;
loadFrame = null;
MapEntity.DeselectAll();
MapEntity.SelectionGroups.Clear();
@@ -786,20 +766,6 @@ namespace Barotrauma
savePath = Path.Combine(Submarine.SavePath, savePath);
}
#if !DEBUG
var vanilla = GameMain.VanillaContent;
if (vanilla != null)
{
var vanillaSubs = vanilla.GetFilesOfType(ContentType.Submarine);
string pathToCompare = savePath.Replace(@"\", @"/").ToLowerInvariant();
if (vanillaSubs.Any(sub => sub.Replace(@"\", @"/").ToLowerInvariant() == pathToCompare))
{
GUI.AddMessage(TextManager.Get("CannotEditVanillaSubs"), Color.Red, font: GUI.LargeFont);
return false;
}
}
#endif
/*foreach (var contentPackage in GameMain.Config.SelectedContentPackages)
{
Submarine.MainSub.RequiredContentPackages.Add(contentPackage.Name);
@@ -2074,10 +2040,6 @@ namespace Barotrauma
dummyCharacter.SelectedConstruction = null;
}
}
else if (MapEntity.SelectedList.Count == 1)
{
(MapEntity.SelectedList[0] as Item)?.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
}
CharacterHUD.Update((float)deltaTime, dummyCharacter, cam);
}
@@ -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.8")]
[assembly: AssemblyFileVersion("0.8.9.8")]
[assembly: AssemblyVersion("0.8.9.6")]
[assembly: AssemblyFileVersion("0.8.9.6")]
@@ -20,10 +20,8 @@ namespace Barotrauma
if (Job != null)
{
msg.Write(Job.Prefab.Identifier);
msg.Write((byte)Job.Skills.Count);
foreach (Skill skill in Job.Skills)
{
msg.Write(skill.Identifier);
msg.Write(skill.Level);
}
}
@@ -15,8 +15,6 @@ namespace Barotrauma
private bool networkUpdateSent;
private double LastInputTime;
public float GetPositionUpdateInterval(Client recipient)
{
if (!Enabled) { return 1000.0f; }
@@ -63,15 +61,6 @@ namespace Barotrauma
else if (memInput.Count == 0)
{
AnimController.Frozen = true;
if (Timing.TotalTime > LastInputTime + 0.5)
{
//no inputs have been received in 0.5 seconds, reset input
//(if there's a temporary network hiccup that prevents us from receiving inputs, we assume the inputs haven't changed,
//but if it takes too long, for example due to a client crashing/disconnecting, we don't want to keep the character
//firing a welding tool or whatever else they were doing until the kill disconnect timer kicks in)
prevDequeuedInput = dequeuedInput =
dequeuedInput.HasFlag(InputNetFlags.FacingLeft) ? InputNetFlags.FacingLeft : InputNetFlags.None;
}
}
else
{
@@ -201,7 +190,6 @@ namespace Barotrauma
networkUpdateID = (ushort)(networkUpdateID - i)
};
memInput.Insert(i, newMem);
LastInputTime = Timing.TotalTime;
}
}
@@ -11,11 +11,11 @@ namespace Barotrauma
{
private List<CharacterCampaignData> characterData = new List<CharacterCampaignData>();
public static void StartNewCampaign(string savePath, string subPath, string seed)
public static void StartNewCampaign(string savePath, string subName, string seed)
{
if (string.IsNullOrWhiteSpace(savePath)) return;
GameMain.GameSession = new GameSession(new Submarine(subPath, ""), savePath,
GameMain.GameSession = new GameSession(new Submarine(subName, ""), savePath,
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
campaign.GenerateMap(seed);
@@ -251,7 +251,6 @@ namespace Barotrauma
}
lastSaveID++;
DebugConsole.Log("Campaign saved, save ID " + lastSaveID);
}
}
}
@@ -1,5 +1,9 @@
using Barotrauma.Networking;
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Barotrauma.Items.Components
{
@@ -10,16 +14,5 @@ namespace Barotrauma.Items.Components
//let the clients know the initial deterioration delay
item.CreateServerEvent(this);
}
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
{
if (c.Character == null) return;
StartRepairing(c.Character);
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(deteriorationTimer);
}
}
}
+2 -12
View File
@@ -20,16 +20,6 @@ namespace Barotrauma
partial void UpdateProjSpecific(float deltaTime, Camera cam)
{
if (IdFreed) { return; }
//don't create updates if all clients are very far from the hull
float hullUpdateDistanceSqr = NetConfig.HullUpdateDistance * NetConfig.HullUpdateDistance;
if (!GameMain.Server.ConnectedClients.Any(c =>
c.Character != null &&
Vector2.DistanceSquared(c.Character.WorldPosition, WorldPosition) < hullUpdateDistanceSqr))
{
return;
}
//update client hulls if the amount of water has changed by >10%
//or if oxygen percentage has changed by 5%
if (Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f ||
@@ -41,8 +31,8 @@ namespace Barotrauma
GameMain.NetworkMember.CreateEntityEvent(this);
lastSentVolume = waterVolume;
lastSentOxygen = OxygenPercentage;
sendUpdateTimer = NetConfig.HullUpdateInterval;
}
sendUpdateTimer = NetworkUpdateInterval;
}
}
}
@@ -46,7 +46,7 @@ namespace Barotrauma.Networking
//when was a specific entity event last sent to the client
// key = event id, value = NetTime.Now when sending
public readonly Dictionary<UInt16, double> EntityEventLastSent = new Dictionary<UInt16, double>();
public readonly Dictionary<UInt16, float> EntityEventLastSent = new Dictionary<UInt16, float>();
//when was a position update for a given entity last sent to the client
// key = entity id, value = NetTime.Now when sending
@@ -187,7 +187,7 @@ namespace Barotrauma.Networking
transfer.WaitTimer -= deltaTime;
if (transfer.WaitTimer > 0.0f) continue;
if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel)) continue;
if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, 1)) continue;
transfer.WaitTimer = 0.05f;// transfer.Connection.AverageRoundtripTime;
@@ -202,6 +202,15 @@ namespace Barotrauma.Networking
{
message = peer.CreateMessage();
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
message.Write((byte)FileTransferMessageType.Initiate);
message.Write((byte)transfer.FileType);
message.Write((ushort)chunkLen);
message.Write((ulong)transfer.Data.Length);
message.Write(transfer.FileName);
GameMain.Server.CompressOutgoingMessage(message);
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
transfer.Status = FileTransferStatus.Sending;
//if the recipient is the owner of the server (= a client running the server from the main exe)
//we don't need to send anything, the client can just read the file directly
@@ -10,7 +10,6 @@ using System.Text;
using System.IO.Compression;
using System.IO;
using Barotrauma.Steam;
using System.Xml.Linq;
namespace Barotrauma.Networking
{
@@ -716,25 +715,23 @@ namespace Barotrauma.Networking
{
string savePath = inc.ReadString();
string seed = inc.ReadString();
string subName = inc.ReadString();
string subHash = inc.ReadString();
string subPath = inc.ReadString();
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
if (matchingSub == null)
if (!File.Exists(subPath))
{
SendDirectChatMessage(
TextManager.Get("CampaignStartFailedSubNotFound").Replace("[subname]", subName),
TextManager.Get("CampaignStartFailedSubNotFound").Replace("[subpath]", subPath),
connectedClient, ChatMessageType.MessageBox);
}
else
{
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.StartNewCampaign(savePath, matchingSub.FilePath, seed);
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.StartNewCampaign(savePath, subPath, seed);
}
}
else
{
string saveName = inc.ReadString();
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.LoadCampaign(saveName);
}
break;
@@ -814,16 +811,7 @@ namespace Barotrauma.Networking
Log(c.Name + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:LevelsDontMatch" + error, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
if (c.Connection == OwnerConnection)
{
SendDirectChatMessage(errorStr, c, ChatMessageType.MessageBox);
EndGame();
}
else
{
KickClient(c, errorStr);
}
KickClient(c, errorStr);
}
public override void CreateEntityEvent(INetSerializable entity, object[] extraData = null)
@@ -1040,7 +1028,7 @@ namespace Barotrauma.Networking
if (command == ClientPermissions.ManageRound && inc.PeekBoolean() &&
GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign)
{
if (!mpCampaign.AllowedToEndRound(sender.Character) && !sender.HasPermission(command))
if (!mpCampaign.AllowedToEndRound(sender.Character))
{
return;
}
@@ -1126,22 +1114,9 @@ namespace Barotrauma.Networking
UInt16 modeIndex = inc.ReadUInt16();
if (GameMain.NetLobbyScreen.GameModes[modeIndex].Identifier.ToLowerInvariant() == "multiplayercampaign")
{
string[] saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer);
for (int i = 0; i < saveFiles.Length; i++)
{
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFiles[i]);
if (doc?.Root != null)
{
saveFiles[i] =
string.Join(";",
saveFiles[i].Replace(';', ' '),
doc.Root.GetAttributeString("submarine", ""),
doc.Root.GetAttributeString("savetime", ""));
}
}
NetOutgoingMessage msg = server.CreateMessage();
msg.Write((byte)ServerPacketHeader.CAMPAIGN_SETUP_INFO);
string[] saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer);
msg.Write((UInt16)saveFiles.Count());
foreach (string saveFile in saveFiles)
{
@@ -1226,7 +1201,6 @@ namespace Barotrauma.Networking
ClientWriteLobby(c);
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign &&
GameMain.NetLobbyScreen.SelectedMode == campaign.Preset &&
NetIdUtils.IdMoreRecent(campaign.LastSaveID, c.LastRecvCampaignSave))
{
//already sent an up-to-date campaign save
@@ -1361,6 +1335,10 @@ namespace Barotrauma.Networking
WriteClientList(c, outmsg);
clientListBytes = outmsg.LengthBytes - clientListBytes;
int eventManagerBytes = outmsg.LengthBytes;
entityEventManager.Write(c, outmsg, out List<NetEntityEvent> sentEvents);
eventManagerBytes = outmsg.LengthBytes - eventManagerBytes;
int chatMessageBytes = outmsg.LengthBytes;
WriteChatMessages(outmsg, c);
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
@@ -1370,8 +1348,7 @@ namespace Barotrauma.Networking
while (!c.NeedsMidRoundSync && c.PendingPositionUpdates.Count > 0)
{
var entity = c.PendingPositionUpdates.Peek();
if (entity == null || entity.Removed ||
(entity is Item item && item.PositionUpdateInterval == float.PositiveInfinity))
if (entity == null || entity.Removed)
{
c.PendingPositionUpdates.Dequeue();
continue;
@@ -1410,55 +1387,25 @@ namespace Barotrauma.Networking
errorMsg +=
" Client list size: " + clientListBytes + " bytes\n" +
" Chat message size: " + chatMessageBytes + " bytes\n" +
" Event size: " + eventManagerBytes + " bytes\n" +
" Position update size: " + positionUpdateBytes + " bytes\n\n";
if (sentEvents != null && sentEvents.Count > 0)
{
errorMsg += "Sent events: \n";
foreach (var entityEvent in sentEvents)
{
errorMsg += " - " + (entityEvent.Entity?.ToString() ?? "null") + "\n";
}
}
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
CompressOutgoingMessage(outmsg);
server.SendMessage(outmsg, c.Connection, NetDeliveryMethod.Unreliable);
//---------------------------------------------------------------------------
for (int i = 0; i < NetConfig.MaxEventPacketsPerUpdate; i++)
{
outmsg = server.CreateMessage();
outmsg.Write((byte)ServerPacketHeader.UPDATE_INGAME);
outmsg.Write((float)NetTime.Now);
int eventManagerBytes = outmsg.LengthBytes;
entityEventManager.Write(c, outmsg, out List<NetEntityEvent> sentEvents);
eventManagerBytes = outmsg.LengthBytes - eventManagerBytes;
if (sentEvents.Count == 0)
{
break;
}
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
if (outmsg.LengthBytes > NetPeerConfiguration.MaximumTransmissionUnit)
{
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + NetPeerConfiguration.MaximumTransmissionUnit + ")\n";
errorMsg +=
" Event size: " + eventManagerBytes + " bytes\n";
if (sentEvents != null && sentEvents.Count > 0)
{
errorMsg += "Sent events: \n";
foreach (var entityEvent in sentEvents)
{
errorMsg += " - " + (entityEvent.Entity?.ToString() ?? "null") + "\n";
}
}
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame2:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
CompressOutgoingMessage(outmsg);
server.SendMessage(outmsg, c.Connection, NetDeliveryMethod.Unreliable);
}
}
private void WriteClientList(Client c, NetOutgoingMessage outmsg)
@@ -1545,8 +1492,7 @@ namespace Barotrauma.Networking
}
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
if (campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
if (campaign != null && NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
{
outmsg.Write(true);
outmsg.WritePadBits();
@@ -164,7 +164,7 @@ namespace Barotrauma.Networking
if (connectedClient != null)
{
Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage);
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid~[status]={status.ToString()}");
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid_[status]={status.ToString()}");
}
}*/
}
@@ -342,7 +342,7 @@ namespace Barotrauma.Networking
if (clVersion != GameMain.Version.ToString())
{
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={clVersion}");
$"DisconnectMessage.InvalidVersion_[version]={GameMain.Version.ToString()}_[clientversion]={clVersion}");
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
@@ -368,7 +368,7 @@ namespace Barotrauma.Networking
if (missingPackages.Count == 1)
{
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage_[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
return;
}
@@ -376,7 +376,7 @@ namespace Barotrauma.Networking
{
List<string> packageStrs = new List<string>();
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages_[missingcontentpackages]={string.Join(", ", packageStrs)}");
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
return;
}
@@ -399,7 +399,7 @@ namespace Barotrauma.Networking
if (incompatiblePackages.Count == 1)
{
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
$"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
$"DisconnectMessage.IncompatibleContentPackage_[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
return;
}
@@ -408,7 +408,7 @@ namespace Barotrauma.Networking
List<string> packageStrs = new List<string>();
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
$"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
$"DisconnectMessage.IncompatibleContentPackages_[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
return;
}
@@ -494,21 +494,13 @@ namespace Barotrauma.Networking
}
else
{
var defaultPerms = PermissionPreset.List.Find(p => p.Name == "None");
if (defaultPerms != null)
{
newClient.SetPermissions(defaultPerms.Permissions, defaultPerms.PermittedCommands);
}
else
{
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
}
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
}
}
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
{
inc.SenderConnection.Disconnect(reason.ToString() + "/ " + TextManager.GetServerMessage(message));
inc.SenderConnection.Disconnect(reason.ToString() + "/ " + message);
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
if (unauthClient != null)
{
@@ -228,7 +228,7 @@ namespace Barotrauma.Networking
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event "
+ (c.LastRecvEntityEventID + 1).ToString() +
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago)" +
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error);
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.ServerMessage);
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncOldEvent");
}
);
@@ -242,7 +242,7 @@ namespace Barotrauma.Networking
toKick.ForEach(c =>
{
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", Color.Red);
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.Error);
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.ServerMessage);
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncRemovedEvent");
});
}
@@ -251,7 +251,7 @@ namespace Barotrauma.Networking
var timedOutClients = clients.FindAll(c => c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut);
foreach (Client timedOutClient in timedOutClients)
{
GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.Error);
GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.ServerMessage);
GameMain.Server.DisconnectClient(timedOutClient, "", "ServerMessage.SyncTimeout");
}
@@ -305,7 +305,19 @@ namespace Barotrauma.Networking
}
//too many events for one packet
if (eventsToSync.Count > 200)
if (eventsToSync.Count > MaxEventsPerWrite)
{
if (eventsToSync.Count > MaxEventsPerWrite * 3 && !client.NeedsMidRoundSync)
{
Color color = eventsToSync.Count > MaxEventsPerWrite * 20 ? Color.Red : Color.Orange;
if (eventsToSync.Count < MaxEventsPerWrite * 5) { color = Color.Yellow; }
DebugConsole.NewMessage("WARNING: event count very high: " + eventsToSync.Count + "/" + MaxEventsPerWrite, color);
}
eventsToSync.RemoveRange(MaxEventsPerWrite, eventsToSync.Count - MaxEventsPerWrite);
}
foreach (NetEntityEvent entityEvent in eventsToSync)
{
if (eventsToSync.Count > 200 && !client.NeedsMidRoundSync)
{
@@ -338,7 +350,7 @@ namespace Barotrauma.Networking
msg.Write(client.UnreceivedEntityEventCount);
msg.Write(client.FirstNewEventID);
Write(msg, eventsToSync, out sentEvents, client);
Write(msg, eventsToSync, client);
}
else
{
@@ -351,6 +363,7 @@ namespace Barotrauma.Networking
(entityEvent as ServerEntityEvent).Sent = true;
client.EntityEventLastSent[entityEvent.ID] = NetTime.Now;
}
sentEvents = eventsToSync;
}
/// <summary>
@@ -374,10 +387,10 @@ namespace Barotrauma.Networking
for (int i = startIndex; i < eventList.Count; i++)
{
//find the first event that hasn't been sent in roundtriptime or at all
client.EntityEventLastSent.TryGetValue(eventList[i].ID, out double lastSent);
//find the first event that hasn't been sent in 1.5 * roundtriptime or at all
client.EntityEventLastSent.TryGetValue(eventList[i].ID, out float lastSent);
float minInterval = Math.Max(client.Connection.AverageRoundtripTime, (float)server.UpdateInterval.TotalSeconds * 2);
float minInterval = Math.Max(client.Connection.AverageRoundtripTime * 1.5f, (float)server.UpdateInterval.TotalSeconds * 2);
if (lastSent > NetTime.Now - Math.Min(minInterval, 0.5f))
{
@@ -403,7 +416,7 @@ namespace Barotrauma.Networking
}
else
{
double midRoundSyncTimeOut = uniqueEvents.Count / 100 * server.UpdateInterval.TotalSeconds;
double midRoundSyncTimeOut = uniqueEvents.Count / MaxEventsPerWrite * server.UpdateInterval.TotalSeconds;
midRoundSyncTimeOut = Math.Max(10.0f, midRoundSyncTimeOut * 10.0f);
client.UnreceivedEntityEventCount = (UInt16)uniqueEvents.Count;
@@ -337,56 +337,37 @@ namespace Barotrauma.Networking
continue;
}
string permissionsStr = clientElement.GetAttributeString("permissions", "");
ClientPermissions permissions = Networking.ClientPermissions.None;
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
if (clientElement.Attribute("preset") == null)
if (permissionsStr.ToLowerInvariant() == "all")
{
string permissionsStr = clientElement.GetAttributeString("permissions", "");
if (permissionsStr.ToLowerInvariant() == "all")
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
permissions |= permission;
}
}
else if (!Enum.TryParse(permissionsStr, out permissions))
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
continue;
}
if (permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
{
foreach (XElement commandElement in clientElement.Elements())
{
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
string commandName = commandElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
if (command == null)
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
continue;
}
permittedCommands.Add(command);
}
permissions |= permission;
}
}
else
else if (!Enum.TryParse(permissionsStr, out permissions))
{
string presetName = clientElement.GetAttributeString("preset", "");
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name == presetName);
if (preset == null)
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
continue;
}
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
if (permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
{
foreach (XElement commandElement in clientElement.Elements())
{
DebugConsole.ThrowError("Failed to restore saved permissions to the client \"" + clientName + "\". Permission preset \"" + presetName + "\" not found.");
return;
}
else
{
permissions = preset.Permissions;
permittedCommands = preset.PermittedCommands.ToList();
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
string commandName = commandElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
if (command == null)
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
continue;
}
permittedCommands.Add(command);
}
}
@@ -459,14 +440,9 @@ namespace Barotrauma.Networking
foreach (SavedClientPermission clientPermission in ClientPermissions)
{
var matchingPreset = PermissionPreset.List.Find(p => p.MatchesPermissions(clientPermission.Permissions, clientPermission.PermittedCommands));
if (matchingPreset != null && matchingPreset.Name == "None")
{
continue;
}
XElement clientElement = new XElement("Client",
new XAttribute("name", clientPermission.Name));
new XAttribute("name", clientPermission.Name),
new XAttribute("permissions", clientPermission.Permissions.ToString()));
if (clientPermission.SteamID > 0)
{
@@ -477,21 +453,14 @@ namespace Barotrauma.Networking
clientElement.Add(new XAttribute("ip", clientPermission.IP));
}
if (matchingPreset == null)
if (clientPermission.Permissions.HasFlag(Barotrauma.Networking.ClientPermissions.ConsoleCommands))
{
clientElement.Add(new XAttribute("permissions", clientPermission.Permissions.ToString()));
if (clientPermission.Permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
{
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
{
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
}
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
}
}
else
{
clientElement.Add(new XAttribute("preset", matchingPreset.Name));
}
doc.Root.Add(clientElement);
}
@@ -56,7 +56,6 @@
<Character file="Content/Characters/Husk/Husk.xml" />
<Character file="Content/Characters/Humanhusk/Humanhusk.xml" />
<Character file="Content/Characters/Legacyhusk/Legacyhusk.xml" />
<Character file="Content/Characters/Legacycharybdis/Legacycharybdis.xml" />
<Character file="Content/Characters/Legacycrawler/Legacycrawler.xml" />
<Character file="Content/Characters/Legacymoloch/Legacymoloch.xml" />
<Character file="Content/Characters/Mudraptor/Mudraptor.xml" />
@@ -71,11 +70,10 @@
<Outpost file="Content/Map/Outposts/Outpost.sub" />
<Submarine file="Submarines/Orca.sub" />
<Submarine file="Submarines/Typhon.sub" />
<Submarine file="Submarines/Selkie.sub" />
<Submarine file="Submarines/Muikku.sub" />
<Submarine file="Submarines/Bunyip.sub" />
<Submarine file="Submarines/Humpback.sub" />
<Submarine file="Submarines/Dugong.sub" />
<Submarine file="Submarines/PAX.sub" />
<Submarine file="Submarines/Remora.sub" />
<Submarine file="Submarines/RemoraDrone.sub" />
<Text file="Content/Texts/EnglishVanilla.xml" />
@@ -13,13 +13,6 @@
<Command name="autorestart"/>
<Command name="autorestartinterval"/>
<Command name="autorestarttimer"/>
<Command name="botcount"/>
<Command name="botspawnmode"/>
<Command name="gamemode"/>
<Command name="sub"/>
<Command name="shuttle"/>
<Command name="water"/>
<Command name="fire"/>
<Command name="difficulty"/>
<Command name="kick"/>
<Command name="kickid"/>
@@ -35,8 +28,6 @@
<Command name="autorestart"/>
<Command name="autorestartinterval"/>
<Command name="autorestarttimer"/>
<Command name="botcount"/>
<Command name="botspawnmode"/>
<Command name="difficulty"/>
<Command name="kick"/>
<Command name="kickid"/>
@@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\Animations\" />
<Folder Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\" />
<Folder Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Animations\" />
<Folder Include="$(MSBuildThisFileDirectory)Content\Characters\Coelanth\Animations\" />
<Folder Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycrawler\" />
<Folder Include="$(MSBuildThisFileDirectory)Content\Characters\Endworm\Animations\" />
@@ -45,27 +45,12 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\Ragdolls\CarrierDefaultRagdoll.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Animations\CharybdisSwimFast.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Animations\CharybdisSwimSlow.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Charybdis.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Charybdis.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Ragdolls\CharybdisDefaultRagdoll.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\Legacycharybdis.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\Ragdolls\LegacycharybdisDefaultRagdoll.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Coelanth\Coelanth.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -357,36 +342,6 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Effects\waterbump.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\1_CommandReactor\BaroTutorial_CommandReactor.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\2_NavConsole\BaroTutorial_NavConsole.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\3_Flood\BaroTutorial_Flood.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\4_Reactor\BaroTutorial_Reactor.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\5_EnemyOnSonar\BaroTutorial_EnemyOnSonar.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\6_Degrading2\BaroTutorial_Degrading.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\7_Medical\BaroTutorial_Medical.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Tutorials\ContextualTutorial\8_Approach1\BaroTutorial_Approach.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\UI\tutorialAtlas.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="$(MSBuildThisFileDirectory)Content\Fonts\BebasNeue-Regular.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="$(MSBuildThisFileDirectory)Content\Fonts\NotoSans\LICENSE_OFL.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -942,13 +897,13 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\Animations\CarrierSwimSlow.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\charybdis.png">
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\charybdis.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\Animations\LegacycharybdisSwimFast.xml">
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Animations\CharybdisSwimFast.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\Animations\LegacycharybdisSwimSlow.xml">
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\Animations\CharybdisSwimSlow.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Characters\Coelanth\Animations\CoelanthSwimFast.xml">
@@ -2000,9 +1955,6 @@
<Content Include="$(MSBuildThisFileDirectory)serversettings.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Misc\GuitarClown.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\CARRIER_alarmLoop.ogg">
@@ -2404,7 +2356,7 @@
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Mudraptor\MUDRAPTOR_idle3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Legacycharybdis\charybdisattack.ogg">
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Charybdis\charybdisattack.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Coelanth\attack1.ogg">
@@ -3162,7 +3114,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Muikku.sub">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Orca.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -3182,9 +3134,6 @@
<None Include="$(MSBuildThisFileDirectory)Submarines\RemoraDrone.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Selkie.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Typhon.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -115,7 +115,7 @@ namespace Barotrauma
SonarLabel = element.GetAttributeString("sonarlabel", "");
}
public AITarget(Entity e, float sightRange = -1, float soundRange = 0)
public AITarget(Entity e)
{
Entity = e;
if (sightRange < 0)
File diff suppressed because it is too large Load Diff
@@ -193,7 +193,7 @@ namespace Barotrauma
// is not attached or is attached to something else
if (!IsAttached || IsAttached && attachJoints[0].BodyB == attachTargetBody)
{
if (Vector2.DistanceSquared(ConvertUnits.ToDisplayUnits(transformedAttachPos), enemyAI.AttackingLimb.WorldPosition) < enemyAI.AttackingLimb.attack.DamageRange * enemyAI.AttackingLimb.attack.DamageRange)
if (Vector2.DistanceSquared(ConvertUnits.ToDisplayUnits(transformedAttachPos), enemyAI.AttackingLimb.WorldPosition) < enemyAI.AttackingLimb.attack.Range * enemyAI.AttackingLimb.attack.Range)
{
AttachToBody(character.AnimController.Collider, attachLimb, attachTargetBody, transformedAttachPos);
}
@@ -115,8 +115,7 @@ namespace Barotrauma
unreachable.Add(goToObjective.Target as Hull);
}
goToObjective = null;
HumanAIController.ObjectiveManager.GetObjective<AIObjectiveIdle>().Wander(deltaTime);
//SteeringManager.SteeringWander();
SteeringManager.SteeringWander();
}
}
else if (currentHull != null)
@@ -99,8 +99,7 @@ namespace Barotrauma
FindTargetItem();
if (targetItem == null || moveToTarget == null)
{
HumanAIController.ObjectiveManager.GetObjective<AIObjectiveIdle>().Wander(deltaTime);
//SteeringManager.SteeringWander();
SteeringManager.SteeringWander();
return;
}
@@ -98,64 +98,60 @@ namespace Barotrauma
PathSteering.Reset();
return;
}
if (standStillTimer < -walkDuration)
{
standStillTimer = Rand.Range(standStillMin, standStillMax);
}
//steer away from edges of the hull
if (character.AnimController.CurrentHull != null && !character.IsClimbing)
{
standStillTimer = Rand.Range(standStillMin, standStillMax);
}
Wander(deltaTime);
return;
}
if (currentTarget != null)
{
character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition);
}
}
public void Wander(float deltaTime)
{
//steer away from edges of the hull
if (character.AnimController.CurrentHull != null && !character.IsClimbing)
{
float leftDist = character.Position.X - character.AnimController.CurrentHull.Rect.X;
float rightDist = character.AnimController.CurrentHull.Rect.Right - character.Position.X;
if (leftDist < WallAvoidDistance && rightDist < WallAvoidDistance)
{
if (Math.Abs(rightDist - leftDist) > WallAvoidDistance / 2)
if (leftDist < WallAvoidDistance && rightDist < WallAvoidDistance)
{
PathSteering.SteeringManual(deltaTime, Vector2.UnitX * Math.Sign(rightDist - leftDist));
if (Math.Abs(rightDist - leftDist) > WallAvoidDistance / 2)
{
PathSteering.SteeringManual(deltaTime, Vector2.UnitX * Math.Sign(rightDist - leftDist));
}
else
{
PathSteering.Reset();
return;
}
}
else if (leftDist < WallAvoidDistance)
{
PathSteering.SteeringManual(deltaTime, Vector2.UnitX * (WallAvoidDistance-leftDist) / WallAvoidDistance);
PathSteering.WanderAngle = 0.0f;
return;
}
else
{
PathSteering.Reset();
PathSteering.SteeringManual(deltaTime, -Vector2.UnitX * (WallAvoidDistance-rightDist) / WallAvoidDistance);
PathSteering.WanderAngle = MathHelper.Pi;
return;
}
}
else if (leftDist < WallAvoidDistance)
character.AIController.SteeringManager.SteeringWander();
if (!character.IsClimbing && !character.AnimController.InWater)
{
//PathSteering.SteeringManual(deltaTime, Vector2.UnitX * (WallAvoidDistance - leftDist) / WallAvoidDistance);
PathSteering.SteeringManual(deltaTime, Vector2.UnitX);
PathSteering.WanderAngle = 0.0f;
}
else if (rightDist < WallAvoidDistance)
{
//PathSteering.SteeringManual(deltaTime, -Vector2.UnitX * (WallAvoidDistance - rightDist) / WallAvoidDistance);
PathSteering.SteeringManual(deltaTime, -Vector2.UnitX);
PathSteering.WanderAngle = MathHelper.Pi;
}
else
{
SteeringManager.SteeringWander();
}
//reset vertical steering to prevent dropping down from platforms etc
character.AIController.SteeringManager.ResetY();
}
return;
}
else
if (currentTarget != null)
{
SteeringManager.SteeringWander();
}
if (!character.IsClimbing && !character.AnimController.InWater)
{
//reset vertical steering to prevent dropping down from platforms etc
character.AIController.SteeringManager.ResetY();
character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition);
}
}
@@ -369,18 +369,9 @@ namespace Barotrauma
return;
}
Vector2 transformedMovement = reverse ? -movement : movement;
float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2;
float mainLimbAngle = 0;
if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue)
{
mainLimbAngle = TorsoAngle.Value;
}
else if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{
mainLimbAngle = HeadAngle.Value;
}
mainLimbAngle *= Dir;
float movementAngle = MathUtils.VectorToAngle(movement) - MathHelper.PiOver2;
float mainLimbAngle = (MainLimb.type == LimbType.Torso ? TorsoAngle.Value : HeadAngle.Value) * Dir;
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) > MathHelper.Pi)
{
movementAngle += MathHelper.TwoPi;
@@ -388,7 +379,7 @@ namespace Barotrauma
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi)
{
movementAngle -= MathHelper.TwoPi;
}
}
if (CurrentSwimParams.RotateTowardsMovement)
{
@@ -412,6 +403,7 @@ namespace Barotrauma
if (TailAngle.HasValue)
{
Limb tail = GetLimb(LimbType.Tail);
//tail?.body.SmoothRotate(movementAngle + TailAngle.Value * Dir, TailTorque);
if (tail != null)
{
SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque);
@@ -421,10 +413,6 @@ namespace Barotrauma
else
{
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
if (reverse)
{
movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi);
}
if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{
Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque);
@@ -454,7 +442,7 @@ namespace Barotrauma
var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude);
if (waveLength > 0 && waveAmplitude > 0)
{
WalkPos -= transformedMovement.Length() / Math.Abs(waveLength);
WalkPos -= movement.Length() / Math.Abs(waveLength);
WalkPos = MathUtils.WrapAngleTwoPi(WalkPos);
}
@@ -697,6 +685,12 @@ namespace Barotrauma
limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength);
}
while (referenceLimb.Rotation - angle < -MathHelper.TwoPi)
{
angle -= MathHelper.TwoPi;
}
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
}
private void SmoothRotateWithoutWrapping(Limb limb, float angle, Limb referenceLimb, float torque)
@@ -1463,6 +1463,11 @@ namespace Barotrauma
targetRightHand.PullJointMaxForce = 5000.0f;
}
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
{
Collider.ResetDynamics();
}
target.AnimController.IgnorePlatforms = true;
}
else
@@ -99,7 +99,7 @@ namespace Barotrauma
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/";
public static string GetDefaultFile(string speciesName, AnimationType animType) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName, animType)}.xml";
public static string GetFolder(string speciesName)
protected static string GetFolder(string speciesName)
{
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
@@ -79,7 +79,7 @@ namespace Barotrauma
new XAttribute("sourcerect", $"0, 0, 1, 1")))
};
public static string GetFolder(string speciesName)
protected static string GetFolder(string speciesName)
{
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
@@ -1035,6 +1035,8 @@ namespace Barotrauma
CheckValidity();
CheckValidity();
UpdateNetPlayerPosition(deltaTime);
CheckDistFromCollider();
UpdateCollisionCategories();
@@ -1295,42 +1297,17 @@ namespace Barotrauma
UpdateProjSpecific(deltaTime);
}
public bool Invalid { get; private set; }
private int validityResets;
private bool CheckValidity()
private void CheckValidity()
{
bool isColliderValid = CheckValidity(Collider);
bool limbsValid = true;
CheckValidity(Collider);
foreach (Limb limb in limbs)
{
if (limb.body == null || !limb.body.Enabled) { continue; }
if (!CheckValidity(limb.body))
{
limbsValid = false;
break;
}
CheckValidity(limb.body);
}
bool isValid = isColliderValid && limbsValid;
if (!isValid)
{
validityResets++;
if (validityResets > 1)
{
Invalid = true;
DebugConsole.ThrowError("Invalid ragdoll physics. Ragdoll freezed to prevent crashes.");
Collider.SetTransform(Vector2.Zero, 0.0f);
foreach (Limb limb in Limbs)
{
limb.body.SetTransform(Collider.SimPosition, 0.0f);
limb.body.ResetDynamics();
}
Frozen = true;
}
}
return isValid;
}
private bool CheckValidity(PhysicsBody body)
private void CheckValidity(PhysicsBody body)
{
string errorMsg = null;
string bodyName = body.UserData is Limb ? "Limb" : "Collider";
@@ -1382,7 +1359,7 @@ namespace Barotrauma
limb.body.ResetDynamics();
}
SetInitialLimbPositions();
return false;
return;
}
return true;
}
@@ -1524,7 +1501,8 @@ namespace Barotrauma
float allowedDist = Math.Max(Math.Max(Collider.radius, Collider.width), Collider.height) * 2.0f;
float resetDist = allowedDist * 5.0f;
float distSqrd = Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition);
Vector2 diff = Collider.SimPosition - MainLimb.SimPosition;
float distSqrd = diff.LengthSquared();
if (distSqrd > resetDist * resetDist)
{
@@ -1535,10 +1513,13 @@ namespace Barotrauma
{
//ragdoll too far from the collider, disable collisions until it's close enough
//(in case the ragdoll has gotten stuck somewhere)
Vector2 forceDir = diff / (float)Math.Sqrt(distSqrd);
foreach (Limb limb in Limbs)
{
if (limb.IsSevered) continue;
limb.body.CollidesWith = Physics.CollisionNone;
limb.body.ApplyForce(forceDir * limb.Mass * 10.0f, maxVelocity: 10.0f);
}
collisionsDisabled = true;
@@ -28,7 +28,6 @@ namespace Barotrauma
public enum AIBehaviorAfterAttack
{
FallBack,
FallBackUntilCanAttack,
PursueIfCanAttack,
Pursue
}
@@ -82,9 +81,6 @@ namespace Barotrauma
[Serialize(AIBehaviorAfterAttack.FallBack, true), Editable(ToolTip = "The preferred AI behavior after the attack.")]
public AIBehaviorAfterAttack AfterAttack { get; private set; }
[Serialize(false, true), Editable(ToolTip = "Should the ai try to reverse when aiming with this attack?")]
public bool Reverse { get; private set; }
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f, ToolTip = "Min distance from the attack limb to the target before the AI tries to attack.")]
public float Range { get; private set; }
@@ -100,9 +96,6 @@ namespace Barotrauma
[Serialize(0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, DecimalCount = 2, ToolTip = "Used as the attack cooldown between different kind of attacks. Does not have effect, if set to 0.")]
public float SecondaryCoolDown { get; private set; } = 0;
[Serialize(0f, true), Editable(MinValueFloat = 0, MaxValueFloat = 1, DecimalCount = 2, ToolTip = "Random factor applied to all cooldowns. Example: 0.1 -> adds a random value between -10% and 10% of the cooldown. Min 0 (default), Max 1 (could disable or double the cooldown in extreme cases).")]
public float CoolDownRandomFactor { get; private set; } = 0;
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)]
public float StructureDamage { get; private set; }
@@ -189,7 +182,7 @@ namespace Barotrauma
public readonly List<Affliction> Afflictions = new List<Affliction>();
/// <summary>
/// Only affects ai decision making. All the conditionals has to be met in order to select the attack. TODO: allow to define conditionals using any (implemented in StatusEffect -> move from there to PropertyConditional?)
/// Only affects ai decision making.
/// </summary>
public List<PropertyConditional> Conditionals { get; private set; } = new List<PropertyConditional>();
@@ -451,10 +444,8 @@ namespace Barotrauma
public void SetCoolDown()
{
float randomFraction = CoolDown * CoolDownRandomFactor;
CoolDownTimer = CoolDown + MathHelper.Lerp(-randomFraction, randomFraction, Rand.Value(Rand.RandSync.Server));
randomFraction = SecondaryCoolDown * CoolDownRandomFactor;
SecondaryCoolDownTimer = SecondaryCoolDown + MathHelper.Lerp(-randomFraction, randomFraction, Rand.Value(Rand.RandSync.Server));
CoolDownTimer = CoolDown;
SecondaryCoolDownTimer = SecondaryCoolDown;
}
public void ResetCoolDown()
@@ -810,7 +810,6 @@ namespace Barotrauma
public void LoadHeadAttachments()
{
if (Info == null) { return; }
if (AnimController == null) { return; }
var head = AnimController.GetLimb(LimbType.Head);
if (head == null) { return; }
@@ -1113,15 +1112,13 @@ namespace Barotrauma
ViewTarget = null;
if (!AllowInput) return;
if (Controlled == this || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer))
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
if (Controlled == this)
{
SmoothedCursorPosition = cursorPosition;
}
else
{
//apply some smoothing to the cursor positions of remote players when playing as a client
//to make aiming look a little less choppy
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
}
@@ -1188,10 +1185,6 @@ namespace Barotrauma
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.F))
{
AnimController.ReleaseStuckLimbs();
if (AIController != null && AIController is EnemyAIController enemyAI)
{
enemyAI.LatchOntoAI?.DeattachFromBody();
}
}
#endif
@@ -1271,7 +1264,15 @@ namespace Barotrauma
if (IsKeyDown(InputType.Aim) && selectedItems[i] != null) selectedItems[i].SecondaryUse(deltaTime, this);
}
}
#if CLIENT
if (SelectedConstruction != null && SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null && HUD.CloseHUD(ic.GuiFrame.Rect)))
{
//emulate a Select input to get the character to deselect the item server-side
keys[(int)InputType.Select].Hit = true;
SelectedConstruction = null;
}
#endif
if (SelectedConstruction != null)
{
if (IsKeyDown(InputType.Use)) SelectedConstruction.Use(deltaTime, this);
@@ -1649,8 +1650,7 @@ namespace Barotrauma
#if CLIENT
if (isLocalPlayer)
{
if (GUI.MouseOn == null &&
(!CharacterInventory.IsMouseOnInventory() || CharacterInventory.DraggingItemToWorld))
if (GUI.MouseOn == null && !CharacterInventory.IsMouseOnInventory())
{
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
{
@@ -1665,12 +1665,10 @@ namespace Barotrauma
focusedItem = null;
}
findFocusedTimer -= deltaTime;
}
}
#endif
//climb ladders automatically when pressing up/down inside their trigger area
Ladder currentLadder = SelectedConstruction?.GetComponent<Ladder>();
if ((SelectedConstruction == null || currentLadder != null) &&
!AnimController.InWater && Screen.Selected != GameMain.SubEditorScreen)
if (SelectedConstruction == null && !AnimController.InWater && Screen.Selected != GameMain.SubEditorScreen)
{
bool climbInput = IsKeyDown(InputType.Up) || IsKeyDown(InputType.Down);
bool isControlled = Controlled == this;
@@ -1681,19 +1679,6 @@ namespace Barotrauma
float minDist = float.PositiveInfinity;
foreach (Ladder ladder in Ladder.List)
{
if (ladder == currentLadder)
{
continue;
}
else if (currentLadder != null)
{
//only switch from ladder to another if the ladders are above the current ladders and pressing up, or vice versa
if (ladder.Item.WorldPosition.Y > currentLadder.Item.WorldPosition.Y != IsKeyDown(InputType.Up))
{
continue;
}
}
if (CanInteractWith(ladder.Item, out float dist, checkLinked: false) && dist < minDist)
{
minDist = dist;
@@ -1710,7 +1695,7 @@ namespace Barotrauma
}
}
if (SelectedCharacter != null && (IsKeyHit(InputType.Grab) || IsKeyHit(InputType.Health))) //Let people use ladders and buttons and stuff when dragging chars
if (SelectedCharacter != null && IsKeyHit(InputType.Grab)) //Let people use ladders and buttons and stuff when dragging chars
{
DeselectCharacter();
}
@@ -804,12 +804,6 @@ namespace Barotrauma
var newItem = Item.Load(itemElement, inventory.Owner.Submarine, createNetworkEvent: true);
if (newItem == null) { continue; }
if (!MathUtils.NearlyEqual(newItem.Condition, newItem.MaxCondition) &&
GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.NetworkMember.CreateEntityEvent(newItem, new object[] { NetEntityEvent.Type.Status });
}
int[] slotIndices = itemElement.GetAttributeIntArray("i", new int[] { 0 });
if (!slotIndices.Any())
{
@@ -153,10 +153,7 @@ namespace Barotrauma
//how high the strength has to be for the affliction icon to be shown in the UI
public readonly float ShowIconThreshold = 0.05f;
public readonly float MaxStrength = 100.0f;
//how high the strength has to be for the affliction icon to be shown with a health scanner
public readonly float ShowInHealthScannerThreshold = 0.05f;
public float BurnOverlayAlpha;
public float DamageOverlayAlpha;
@@ -260,8 +257,6 @@ namespace Barotrauma
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", Math.Max(ActivationThreshold, 0.05f));
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
ShowInHealthScannerThreshold = element.GetAttributeFloat("showinhealthscannerthreshold", Math.Max(ActivationThreshold, 0.05f));
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
@@ -460,7 +460,6 @@ namespace Barotrauma
{
affliction.Strength = 0.0f;
}
CalculateVitality();
}
private void AddLimbAffliction(Limb limb, Affliction newAffliction)
@@ -520,15 +520,14 @@ namespace Barotrauma
// Ignore blocking on items, because it causes cases where a Mudraptor cannot hit the hatch, for example.
wasHit = true;
}
else if (damageTarget is Structure wall && structureBody != null &&
(structureBody.UserData is Structure || (structureBody.UserData is Submarine sub && sub == wall.Submarine)))
else if (damageTarget is Structure && structureBody?.UserData is Structure)
{
// If the attack is aimed to a structure (wall) and hits a structure or the sub, it's successful
// If the attack is aimed to a structure and hits a structure, it's successful
wasHit = true;
}
else
{
// If there is nothing between, the hit is successful
// If the attack is aimed to a character but hits a structure, the hit is blocked.
wasHit = structureBody == null;
}
}
@@ -103,6 +103,12 @@ namespace Barotrauma
if (missionType == MissionType.Random)
{
allowedMissions.AddRange(MissionPrefab.List);
#if SERVER
if (GameMain.Server != null)
{
allowedMissions.RemoveAll(mission => !GameMain.Server.ServerSettings.AllowedRandomMissionTypes.Contains(mission.type));
}
#endif
}
else if (missionType == MissionType.None)
{
@@ -118,11 +124,6 @@ namespace Barotrauma
{
allowedMissions.RemoveAll(m => !m.IsAllowed(locations[0], locations[1]));
}
if (allowedMissions.Count == 0)
{
return null;
}
int probabilitySum = allowedMissions.Sum(m => m.Commonness);
int randomNumber = rand.NextInt32() % probabilitySum;
@@ -139,7 +139,7 @@ namespace Barotrauma
MTRandom rand = new MTRandom(ToolBox.StringToInt(seed));
for (int i = 0; i < 2; i++)
{
dummyLocations[i] = Location.CreateRandom(new Vector2((float)rand.NextDouble() * 10000.0f, (float)rand.NextDouble() * 10000.0f), null, rand);
dummyLocations[i] = Location.CreateRandom(new Vector2((float)rand.NextDouble() * 10000.0f, (float)rand.NextDouble() * 10000.0f), null);
}
}
@@ -208,7 +208,7 @@ namespace Barotrauma
DockingPort myPort = null, outPostPort = null;
foreach (DockingPort port in DockingPort.List)
{
if (port.IsHorizontal || port.Docked) { continue; }
if (port.IsHorizontal) { continue; }
if (port.Item.Submarine == level.StartOutpost)
{
outPostPort = port;
@@ -880,7 +880,8 @@ namespace Barotrauma.Items.Components
List<MapEntity> linked = new List<MapEntity>(item.linkedTo);
foreach (MapEntity entity in linked)
{
if (!(entity is Item linkedItem)) { continue; }
Item linkedItem = entity as Item;
if (linkedItem == null) { continue; }
var dockingPort = linkedItem.GetComponent<DockingPort>();
if (dockingPort != null)
@@ -426,11 +426,11 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null)
{
if (!attachable || item.body == null) { return character == null || character.IsKeyDown(InputType.Aim); }
if (!attachable || item.body == null) return (character == null || character.IsKeyDown(InputType.Aim));
if (character != null)
{
if (!character.IsKeyDown(InputType.Aim)) { return false; }
if (!CanBeAttached()) { return false; }
if (!character.IsKeyDown(InputType.Aim)) return false;
if (!CanBeAttached()) return false;
#if SERVER
if (GameMain.Server != null)
{
@@ -438,12 +438,7 @@ namespace Barotrauma.Items.Components
GameServer.Log(character.LogName + " attached " + item.Name + " to a wall", ServerLog.MessageType.ItemInteraction);
}
#endif
}
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
if (character != null) { item.Drop(character); }
AttachToWall();
item.Drop(character);
}
return true;
@@ -555,7 +550,7 @@ namespace Barotrauma.Items.Components
public override void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
base.ServerWrite(msg, c, extraData);
if (!attachable || body == null) { return; }
if (!attachable || body == null) return;
msg.Write(Attached);
msg.Write(body.SimPosition.X);
@@ -2,15 +2,12 @@
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class LevelResource : ItemComponent, IServerSerializable
{
private float lastSentDeattachTimer;
[Serialize(1.0f, false)]
public float DeattachDuration
{
@@ -24,29 +21,12 @@ namespace Barotrauma.Items.Components
get { return deattachTimer; }
set
{
//clients don't deattach the item until the server says so (handled in ClientRead)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
{
return;
}
deattachTimer = Math.Max(0.0f, value);
#if SERVER
if (deattachTimer >= DeattachDuration)
{
if (holdable.Attached){ item.CreateServerEvent(this); }
holdable.DeattachFromWall();
}
else if (Math.Abs(lastSentDeattachTimer - deattachTimer) > 0.1f)
{
item.CreateServerEvent(this);
lastSentDeattachTimer = deattachTimer;
}
#else
if (deattachTimer >= DeattachDuration)
//clients don't deattach the item until the server says so (handled in ClientRead)
if ((GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) && deattachTimer >= DeattachDuration)
{
holdable.DeattachFromWall();
}
#endif
}
}
@@ -87,10 +67,7 @@ namespace Barotrauma.Items.Components
return;
}
holdable.Reattachable = false;
if (requiredItems.Any())
{
holdable.PickingTime = float.MaxValue;
}
holdable.PickingTime = float.MaxValue;
var body = item.body ?? holdable.Body;
@@ -17,8 +17,6 @@ namespace Barotrauma.Items.Components
private readonly List<string> fixableEntities;
private Vector2 pickedPosition;
private float activeTimer;
private Vector2 debugRayStartPos, debugRayEndPos;
[Serialize(0.0f, false)]
public float Range { get; set; }
@@ -158,7 +156,7 @@ namespace Barotrauma.Items.Components
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;
if (RepairThroughWalls)
{
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false);
foreach (Body body in bodies)
{
FixBody(user, deltaTime, degreeOfSuccess, body);
@@ -166,7 +164,7 @@ namespace Barotrauma.Items.Components
}
else
{
FixBody(user, deltaTime, degreeOfSuccess, Submarine.PickBody(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true));
FixBody(user, deltaTime, degreeOfSuccess, Submarine.PickBody(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false));
}
if (ExtinguishAmount > 0.0f && item.CurrentHull != null)
@@ -249,7 +247,6 @@ namespace Barotrauma.Items.Components
var levelResource = targetItem.GetComponent<LevelResource>();
if (levelResource != null && levelResource.IsActive &&
levelResource.requiredItems.Any() &&
levelResource.HasRequiredItems(user, addMessage: false))
{
levelResource.DeattachTimer += deltaTime;
@@ -104,8 +104,8 @@ namespace Barotrauma.Items.Components
#if SERVER
GameServer.Log(picker.LogName + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
#endif
Character thrower = picker;
item.Drop(thrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
item.Drop(picker, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector*10.0f);
@@ -189,7 +189,7 @@ namespace Barotrauma.Items.Components
{
get { return name; }
}
[Editable, Serialize("", true)]
public string Msg
{
@@ -203,6 +203,12 @@ namespace Barotrauma.Items.Components
set;
}
public AITarget AITarget
{
get;
private set;
}
public AITarget AITarget
{
get;
@@ -247,7 +253,7 @@ namespace Barotrauma.Items.Components
{
DebugConsole.ThrowError("Invalid pick key in " + element + "!", e);
}
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
ParseMsg();
@@ -155,14 +155,13 @@ namespace Barotrauma.Items.Components
{
if (item.Container != null) { return false; }
if (AutoInteractWithContained && character.SelectedConstruction == null)
if (AutoInteractWithContained)
{
foreach (Item contained in Inventory.Items)
{
if (contained == null) continue;
if (contained.TryInteract(character))
{
character.FocusedItem = contained;
return false;
}
}
@@ -179,7 +178,6 @@ namespace Barotrauma.Items.Components
if (contained == null) continue;
if (contained.TryInteract(picker))
{
picker.FocusedItem = contained;
return true;
}
}
@@ -90,7 +90,7 @@ namespace Barotrauma.Items.Components
Force = MathHelper.Lerp(force, (voltage < minVoltage) ? 0.0f : targetForce, 0.1f);
if (Math.Abs(Force) > 1.0f)
{
Vector2 currForce = new Vector2((force / 10.0f) * maxForce * Math.Min(voltage / minVoltage, 1.0f), 0.0f);
Vector2 currForce = new Vector2((force / 100.0f) * maxForce * Math.Min(voltage / minVoltage, 1.0f), 0.0f);
//less effective when in a bad condition
currForce *= MathHelper.Lerp(0.5f, 2.0f, item.Condition / item.MaxCondition);
@@ -49,7 +49,7 @@ namespace Barotrauma.Items.Components
private bool shutDown;
const float AIUpdateInterval = 0.2f;
const float AIUpdateInterval = 1.0f;
private float aiUpdateTimer;
private Character lastUser;
@@ -209,10 +209,10 @@ namespace Barotrauma.Items.Components
allowedFissionRate = Vector2.Lerp(new Vector2(20, AvailableFuel), new Vector2(10, AvailableFuel), degreeOfSuccess);
allowedFissionRate.X = Math.Min(allowedFissionRate.X, allowedFissionRate.Y - 10);
float heatAmount = GetGeneratedHeat(fissionRate);
float heatAmount = fissionRate * (AvailableFuel / 100.0f) * 2.0f;
float temperatureDiff = (heatAmount - turbineOutput) - Temperature;
Temperature += MathHelper.Clamp(Math.Sign(temperatureDiff) * 10.0f * deltaTime, -Math.Abs(temperatureDiff), Math.Abs(temperatureDiff));
//if (item.InWater && AvailableFuel < 100.0f) Temperature -= 12.0f * deltaTime;
if (item.InWater && AvailableFuel < 100.0f) Temperature -= 12.0f * deltaTime;
FissionRate = MathHelper.Lerp(fissionRate, Math.Min(targetFissionRate, AvailableFuel), deltaTime);
TurbineOutput = MathHelper.Lerp(turbineOutput, targetTurbineOutput, deltaTime);
@@ -313,48 +313,6 @@ namespace Barotrauma.Items.Components
}
}
private float GetGeneratedHeat(float fissionRate)
{
return fissionRate * (prevAvailableFuel / 100.0f) * 2.0f;
}
/// <summary>
/// Do we need more fuel to generate enough power to match the current load.
/// </summary>
/// <param name="minimumOutputRatio">How low we allow the output/load ratio to go before loading more fuel.
/// 1.0 = always load more fuel when maximum output is too low, 0.5 = load more if max output is 50% of the load</param>
private bool NeedMoreFuel(float minimumOutputRatio)
{
if (prevAvailableFuel <= 0.0f && load > 0.0f)
{
return true;
}
//fission rate is clamped to the amount of available fuel
float maxFissionRate = Math.Min(prevAvailableFuel, 100.0f);
float maxTurbineOutput = 100.0f;
//calculate the maximum output if the fission rate is cranked as high as it goes and turbine output is at max
float theoreticalMaxHeat = GetGeneratedHeat(fissionRate: maxFissionRate);
float temperatureFactor = Math.Min(theoreticalMaxHeat / 50.0f, 1.0f);
float theoreticalMaxOutput = Math.Min(maxTurbineOutput / 100.0f, temperatureFactor) * MaxPowerOutput;
//maximum output not enough, we need more fuel
return theoreticalMaxOutput < load * minimumOutputRatio;
}
private bool TooMuchFuel()
{
var containedItems = item.ContainedItems;
if (containedItems != null && containedItems.Count() <= 1) { return false; }
//get the amount of heat we'd generate if the fission rate was at the low end of the optimal range
float minimumHeat = GetGeneratedHeat(optimalFissionRate.X);
//if we need a very high turbine output to keep the engine from overheating, there's too much fuel
return minimumHeat > Math.Min(correctTurbineOutput * 1.5f, 90);
}
private void UpdateFailures(float deltaTime)
{
if (temperature > allowedTemperature.Y)
@@ -409,11 +367,6 @@ namespace Barotrauma.Items.Components
targetFissionRate = Math.Min(targetFissionRate + speed * 2 * deltaTime, 100.0f);
}
targetFissionRate = MathHelper.Clamp(targetFissionRate, 0.0f, 100.0f);
//don't push the target too far from the current fission rate
//otherwise we may "overshoot", cranking the target fission rate all the way up because it takes a while
//for the actual fission rate and temperature to follow
targetFissionRate = MathHelper.Clamp(targetFissionRate, FissionRate - 5, FissionRate + 5);
}
public override void UpdateBroken(float deltaTime, Camera cam)
@@ -488,18 +441,12 @@ namespace Barotrauma.Items.Components
}
}
if (aiUpdateTimer > 0.0f)
{
aiUpdateTimer -= deltaTime;
return false;
}
//load more fuel if the current maximum output is only 50% of the current load
if (NeedMoreFuel(minimumOutputRatio: 0.5f))
//we need more fuel
if (-currPowerConsumption < load * 0.5f && prevAvailableFuel <= 0.0f)
{
var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "fuelrod", "reactorfuel" }, item.GetComponent<ItemContainer>())
{
MinContainedAmount = item.ContainedItems.Count(i => i != null && i.Prefab.Identifier == "fuelrod" || i.HasTag("reactorfuel")) + 1,
MinContainedAmount = containedItems.Count(i => i != null && i.Prefab.Identifier == "fuelrod" || i.HasTag("reactorfuel")) + 1,
GetItemPriority = (Item fuelItem) =>
{
if (fuelItem.ParentInventory?.Owner is Item)
@@ -514,7 +461,6 @@ namespace Barotrauma.Items.Components
character?.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f);
aiUpdateTimer = AIUpdateInterval;
return false;
}
else if (TooMuchFuel())
@@ -533,6 +479,12 @@ namespace Barotrauma.Items.Components
}
}
if (aiUpdateTimer > 0.0f)
{
aiUpdateTimer -= deltaTime;
return false;
}
if (lastUser != character && lastUser != null && lastUser.SelectedConstruction == item)
{
character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
@@ -554,7 +506,7 @@ namespace Barotrauma.Items.Components
{
AutoTemp = false;
unsentChanges = true;
UpdateAutoTemp(MathHelper.Lerp(0.5f, 2.0f, degreeOfSuccess), 1.0f);
UpdateAutoTemp(2.0f + degreeOfSuccess * 5.0f, 1.0f);
}
#if CLIENT
onOffSwitch.BarScroll = 0.0f;
@@ -153,7 +153,7 @@ namespace Barotrauma.Items.Components
}
continue;
}
if (!pt.IsActive || !pt.CanTransfer) { continue; }
if (!pt.IsActive) { continue; }
gridLoad += pt.PowerLoad;
gridPower -= pt.CurrPowerConsumption;
@@ -209,9 +209,9 @@ namespace Barotrauma.Items.Components
Charge -= CurrPowerOutput / 3600.0f;
}
item.SendSignal(0, ((int)Charge).ToString(), "charge", null);
item.SendSignal(0, ((int)((Charge / capacity) * 100)).ToString(), "charge_%", null);
item.SendSignal(0, ((int)((RechargeSpeed / maxRechargeSpeed) * 100)).ToString(), "charge_rate", null);
item.SendSignal(0, Charge.ToString(), "charge", null);
item.SendSignal(0, ((Charge / capacity) * 100).ToString(), "charge_%", null);
item.SendSignal(0, ((RechargeSpeed / maxRechargeSpeed) * 100).ToString(), "charge_rate", null);
foreach (Pair<Powered, Connection> connected in directlyConnected)
{
@@ -180,8 +180,7 @@ namespace Barotrauma.Items.Components
#endif
//items in a bad condition are more sensitive to overvoltage
float maxOverVoltage = MathHelper.Lerp(OverloadVoltage * 0.75f, OverloadVoltage, item.Condition / item.MaxCondition);
maxOverVoltage = Math.Max(OverloadVoltage, 1.0f);
float maxOverVoltage = MathHelper.Lerp(Math.Min(OverloadVoltage, 1.0f), OverloadVoltage, item.Condition / item.MaxCondition);
//if the item can't be fixed, don't allow it to break
if (!item.Repairables.Any() || !CanBeOverloaded) continue;
@@ -320,13 +319,7 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
//float maxPower = this is RelayComponent relayComponent ? relayComponent.MaxPower : float.PositiveInfinity;
RelayComponent thisRelayComponent = this as RelayComponent;
if (thisRelayComponent != null)
{
clampPower = Math.Min(Math.Min(clampPower, thisRelayComponent.MaxPower), powerLoad);
clampLoad = Math.Min(clampLoad, thisRelayComponent.MaxPower);
}
float maxPower = this is RelayComponent relayComponent ? relayComponent.MaxPower : float.PositiveInfinity;
foreach (Connection c in PowerConnections)
{
@@ -364,8 +357,6 @@ namespace Barotrauma.Items.Components
continue;
}
float addLoad = 0.0f;
float addPower = 0.0f;
if (powered is PowerContainer powerContainer)
{
if (recipient.Name == "power_in")
@@ -374,7 +365,7 @@ namespace Barotrauma.Items.Components
}
else
{
addPower = powerContainer.CurrPowerOutput;
fullPower += Math.Min(powerContainer.CurrPowerOutput, maxPower);
}
}
else
@@ -389,16 +380,10 @@ namespace Barotrauma.Items.Components
//negative power consumption = the construction is a
//generator/battery or another junction box
{
addPower -= powered.CurrPowerConsumption;
fullPower -= Math.Max(powered.CurrPowerConsumption, -maxPower);
}
}
if (addPower + fullPower > clampPower) { addPower -= (addPower + fullPower) - clampPower; };
if (addPower > 0) { fullPower += addPower; }
if (addLoad + fullLoad > clampLoad) { addLoad -= (addLoad + fullLoad) - clampLoad; };
if (addLoad > 0) { fullLoad += addLoad; }
}
}
}
}
}
@@ -12,6 +12,8 @@ namespace Barotrauma.Items.Components
public static float SkillIncreaseMultiplier = 0.4f;
private string header;
private float fixDurationLowSkill, fixDurationHighSkill;
private float deteriorationTimer;
@@ -50,20 +52,17 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The amount of time it takes to fix the item with insufficient skill levels.")]
public float FixDurationLowSkill
/*private float repairProgress;
public float RepairProgress
{
get;
set;
}
[Serialize(10.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The amount of time it takes to fix the item with sufficient skill levels.")]
public float FixDurationHighSkill
{
get;
set;
}
get { return repairProgress; }
set
{
repairProgress = MathHelper.Clamp(value, 0.0f, 1.0f);
if (repairProgress >= 1.0f && currentFixer != null) currentFixer.AnimController.Anim = AnimController.Animation.None;
}
}*/
private Character currentFixer;
public Character CurrentFixer
{
@@ -84,6 +83,8 @@ namespace Barotrauma.Items.Components
this.item = item;
header = element.GetAttributeString("name", "");
fixDurationLowSkill = element.GetAttributeFloat("fixdurationlowskill", 100.0f);
fixDurationHighSkill = element.GetAttributeFloat("fixdurationhighskill", 5.0f);
InitProjSpecific(element);
}
@@ -159,7 +160,7 @@ namespace Barotrauma.Items.Components
}
bool wasBroken = !item.IsFullCondition;
float fixDuration = MathHelper.Lerp(FixDurationLowSkill, FixDurationHighSkill, successFactor);
float fixDuration = MathHelper.Lerp(fixDurationLowSkill, fixDurationHighSkill, successFactor);
if (fixDuration <= 0.0f)
{
item.Condition = item.MaxCondition;
@@ -185,5 +186,26 @@ namespace Barotrauma.Items.Components
{
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(deteriorationTimer);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
deteriorationTimer = msg.ReadSingle();
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
//no need to write anything, just letting the server know we started repairing
}
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
{
if (c.Character == null) return;
StartRepairing(c.Character);
}
}
}
@@ -163,14 +163,6 @@ namespace Barotrauma.Items.Components
{
wires[index] = wire;
recipientsDirty = true;
if (wire != null)
{
var otherConnection = wire.OtherConnection(this);
if (otherConnection != null)
{
otherConnection.recipientsDirty = true;
}
}
}
public void SendSignal(int stepsTaken, string signal, Item source, Character sender, float power, float signalStrength = 1.0f)
@@ -356,7 +356,7 @@ namespace Barotrauma.Items.Components
projectile.body.ResetDynamics();
projectile.body.Enabled = true;
projectile.SetTransform(ConvertUnits.ToSimUnits(new Vector2(item.WorldRect.X + transformedBarrelPos.X, item.WorldRect.Y - transformedBarrelPos.Y)), -rotation);
projectile.UpdateTransform();
projectile.FindHull();
projectile.Submarine = projectile.body.Submarine;
Projectile projectileComponent = projectile.GetComponent<Projectile>();
@@ -59,7 +59,7 @@ namespace Barotrauma
public PhysicsBody body;
public readonly XElement StaticBodyConfig;
private float lastSentCondition;
private float sendConditionUpdateTimer;
private bool conditionUpdatePending;
@@ -211,14 +211,14 @@ namespace Barotrauma
set { spriteColor = value; }
}
[Serialize("1.0,1.0,1.0,1.0", true), Editable]
[Serialize("1.0,1.0,1.0,1.0", false), Editable]
public Color InventoryIconColor
{
get;
protected set;
}
[Serialize("1.0,1.0,1.0,1.0", true), Editable(ToolTip = "Changes the color of the item this item is contained inside. Only has an effect if either of the UseContainedSpriteColor or UseContainedInventoryIconColor property of the container is set to true.")]
[Serialize("1.0,1.0,1.0,1.0", false), Editable(ToolTip = "Changes the color of the item this item is contained inside. Only has an effect if either of the UseContainedSpriteColor or UseContainedInventoryIconColor property of the container is set to true.")]
public Color ContainerColor
{
get;
@@ -274,11 +274,12 @@ namespace Barotrauma
SetActiveSprite();
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && !MathUtils.NearlyEqual(lastSentCondition, condition))
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && lastSentCondition != condition)
{
if (Math.Abs(lastSentCondition - condition) > 1.0f || condition == 0.0f || condition == Prefab.Health)
{
conditionUpdatePending = true;
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
lastSentCondition = condition;
}
}
}
@@ -995,21 +996,6 @@ namespace Barotrauma
aiTarget.SightRange -= deltaTime * 1000.0f;
aiTarget.SoundRange -= deltaTime * 1000.0f;
}
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
sendConditionUpdateTimer -= deltaTime;
if (conditionUpdatePending)
{
if (sendConditionUpdateTimer <= 0.0f)
{
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
lastSentCondition = condition;
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
conditionUpdatePending = false;
}
}
}
ApplyStatusEffects(ActionType.Always, deltaTime, null);

Some files were not shown because too many files have changed in this diff Show More