(f2e516dfe) v0.9.3.2
This commit is contained in:
@@ -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.9.2.1")]
|
||||
[assembly: AssemblyFileVersion("0.9.2.1")]
|
||||
[assembly: AssemblyVersion("0.9.3.2")]
|
||||
[assembly: AssemblyFileVersion("0.9.3.2")]
|
||||
|
||||
@@ -105,15 +105,15 @@ namespace Barotrauma
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 0);
|
||||
msg.WriteRangedInteger(0, 0, 3);
|
||||
Inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 1);
|
||||
msg.WriteRangedInteger(1, 0, 3);
|
||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 2);
|
||||
msg.WriteRangedInteger(2, 0, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace Barotrauma
|
||||
msg.Write(inputCount);
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, (int)InputNetFlags.MaxVal, (int)memInput[i].states);
|
||||
msg.WriteRangedInteger((int)memInput[i].states, 0, (int)InputNetFlags.MaxVal);
|
||||
msg.Write(memInput[i].intAim);
|
||||
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
|
||||
memInput[i].states.HasFlag(InputNetFlags.Deselect) ||
|
||||
@@ -283,9 +283,16 @@ namespace Barotrauma
|
||||
case 0:
|
||||
if (Inventory == null)
|
||||
{
|
||||
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ")";
|
||||
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
|
||||
//read anyway to prevent messing up reading the rest of the message
|
||||
byte itemCount = msg.ReadByte();
|
||||
for (int i = 0; i < itemCount; i++)
|
||||
{
|
||||
msg.ReadUInt16();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -337,7 +344,7 @@ namespace Barotrauma
|
||||
|
||||
public static Character ReadSpawnData(IReadMessage inc, bool spawn = true)
|
||||
{
|
||||
DebugConsole.NewMessage("READING CHARACTER SPAWN DATA", Color.Cyan);
|
||||
DebugConsole.Log("Reading character spawn data");
|
||||
|
||||
if (GameMain.Client == null) return null;
|
||||
|
||||
@@ -433,7 +440,16 @@ namespace Barotrauma
|
||||
if (causeOfDeathType == CauseOfDeathType.Affliction)
|
||||
{
|
||||
int afflictionIndex = msg.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1);
|
||||
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
|
||||
if (afflictionIndex < 0 || afflictionIndex >= AfflictionPrefab.List.Count)
|
||||
{
|
||||
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction index out of bounds (index: {afflictionIndex}, affliction count: {AfflictionPrefab.List.Count})";
|
||||
causeOfDeathType = CauseOfDeathType.Unknown;
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
|
||||
}
|
||||
}
|
||||
|
||||
byte severedLimbCount = msg.ReadByte();
|
||||
@@ -452,13 +468,20 @@ namespace Barotrauma
|
||||
for (int i = 0; i < severedLimbCount; i++)
|
||||
{
|
||||
int severedJointIndex = msg.ReadByte();
|
||||
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
|
||||
if (severedJointIndex < 0 || severedJointIndex >= AnimController.LimbJoints.Length)
|
||||
{
|
||||
string errorMsg = $"Error in CharacterNetworking.ReadStatus: severed joint index out of bounds (index: {severedJointIndex}, joint count: {AnimController.LimbJoints.Length})";
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsDead) Revive();
|
||||
|
||||
if (IsDead) { Revive(); }
|
||||
CharacterHealth.ClientRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1359,7 +1359,7 @@ namespace Barotrauma
|
||||
}
|
||||
ShowQuestionPrompt("Permission to grant to client #" + id + "?", (perm) =>
|
||||
{
|
||||
GameMain.Client.SendConsoleCommand("giveperm " + id + " " + perm);
|
||||
GameMain.Client?.SendConsoleCommand("giveperm " + id + " " + perm);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1384,7 +1384,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Permission to revoke from client #" + id + "?", (perm) =>
|
||||
{
|
||||
GameMain.Client.SendConsoleCommand("revokeperm " + id + " " + perm);
|
||||
GameMain.Client?.SendConsoleCommand("revokeperm " + id + " " + perm);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1408,7 +1408,7 @@ namespace Barotrauma
|
||||
}
|
||||
ShowQuestionPrompt("Rank to grant to client #" + id + "?", (rank) =>
|
||||
{
|
||||
GameMain.Client.SendConsoleCommand("giverank " + id + " " + rank);
|
||||
GameMain.Client?.SendConsoleCommand("giverank " + id + " " + rank);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1427,7 +1427,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Console command permissions to grant to client #" + id + "? You may enter multiple commands separated with a space.", (commandNames) =>
|
||||
{
|
||||
GameMain.Client.SendConsoleCommand("givecommandperm " + id + " " + commandNames);
|
||||
GameMain.Client?.SendConsoleCommand("givecommandperm " + id + " " + commandNames);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1446,7 +1446,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Console command permissions to revoke from client #" + id + "? You may enter multiple commands separated with a space.", (commandNames) =>
|
||||
{
|
||||
GameMain.Client.SendConsoleCommand("revokecommandperm " + id + " " + commandNames);
|
||||
GameMain.Client?.SendConsoleCommand("revokecommandperm " + id + " " + commandNames);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1487,7 +1487,7 @@ namespace Barotrauma
|
||||
banDuration = parsedBanDuration;
|
||||
}
|
||||
|
||||
GameMain.Client.SendConsoleCommand(
|
||||
GameMain.Client?.SendConsoleCommand(
|
||||
"banendpoint " +
|
||||
args[0] + " " +
|
||||
(banDuration.HasValue ? banDuration.Value.TotalSeconds.ToString() : "0") + " " +
|
||||
@@ -1538,7 +1538,7 @@ namespace Barotrauma
|
||||
NewMessage("Index out of bounds!", Color.Red);
|
||||
return;
|
||||
}
|
||||
GameMain.Client.SendConsoleCommand("campaigndestination " + destinationIndex);
|
||||
GameMain.Client?.SendConsoleCommand("campaigndestination " + destinationIndex);
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -32,6 +32,12 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool IsCJK
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public uint Size
|
||||
{
|
||||
get
|
||||
@@ -58,11 +64,16 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public ScalableFont(XElement element, GraphicsDevice gd = null)
|
||||
: this (element.GetAttributeString("file", ""), (uint)element.GetAttributeInt("size", 14), gd, element.GetAttributeBool("dynamicloading", false))
|
||||
{
|
||||
: this(
|
||||
element.GetAttributeString("file", ""),
|
||||
(uint)element.GetAttributeInt("size", 14),
|
||||
gd,
|
||||
element.GetAttributeBool("dynamicloading", false),
|
||||
element.GetAttributeBool("iscjk", false))
|
||||
{
|
||||
}
|
||||
|
||||
public ScalableFont(string filename, uint size, GraphicsDevice gd = null, bool dynamicLoading = false)
|
||||
public ScalableFont(string filename, uint size, GraphicsDevice gd = null, bool dynamicLoading = false, bool isCJK = false)
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
@@ -85,6 +96,7 @@ namespace Barotrauma
|
||||
this.textures = new List<Texture2D>();
|
||||
this.texCoords = new Dictionary<uint, GlyphData>();
|
||||
this.DynamicLoading = dynamicLoading;
|
||||
this.IsCJK = isCJK;
|
||||
this.graphicsDevice = gd;
|
||||
|
||||
if (gd != null && !dynamicLoading)
|
||||
|
||||
@@ -83,6 +83,7 @@ namespace Barotrauma
|
||||
public static ScalableFont VideoTitleFont => Style?.VideoTitleFont;
|
||||
public static ScalableFont ObjectiveTitleFont => Style?.ObjectiveTitleFont;
|
||||
public static ScalableFont ObjectiveNameFont => Style?.ObjectiveNameFont;
|
||||
public static ScalableFont CJKFont { get; private set; }
|
||||
|
||||
public static UISprite UIGlow => Style.UIGlow;
|
||||
|
||||
@@ -154,6 +155,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.graphicsDevice = graphicsDevice;
|
||||
var uiStyles = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle).ToList();
|
||||
|
||||
if (uiStyles.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("No UI styles defined in the selected content package!");
|
||||
@@ -165,6 +167,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Style = new GUIStyle(uiStyles[0], graphicsDevice);
|
||||
if (CJKFont == null)
|
||||
{
|
||||
CJKFont = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
|
||||
Font.Size, graphicsDevice, dynamicLoading: true, isCJK: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadContent(bool loadSounds = true)
|
||||
@@ -408,7 +415,7 @@ namespace Barotrauma
|
||||
|
||||
if (Character.Controlled?.Inventory != null)
|
||||
{
|
||||
if (!Character.Controlled.LockHands && Character.Controlled.Stun >= -0.1f && !Character.Controlled.IsDead)
|
||||
if (!Character.Controlled.LockHands && Character.Controlled.Stun < 0.1f && !Character.Controlled.IsDead)
|
||||
{
|
||||
Inventory.DrawFront(spriteBatch);
|
||||
}
|
||||
@@ -1563,9 +1570,10 @@ namespace Barotrauma
|
||||
button.OnClicked += (btn, userData) =>
|
||||
{
|
||||
var quitButton = button;
|
||||
if (GameMain.GameSession != null)
|
||||
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen charEditScreen || Screen.Selected is SubEditorScreen subEditScreen))
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuQuitVerification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
|
||||
string text = GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification";
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get(text), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
|
||||
{
|
||||
UserData = "verificationprompt"
|
||||
};
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Visible) return;
|
||||
base.Update(deltaTime);
|
||||
if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && Enabled && GUI.IsMouseOn(this))
|
||||
if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && CanBeFocused && Enabled && GUI.IsMouseOn(this))
|
||||
{
|
||||
state = ComponentState.Hover;
|
||||
if (PlayerInput.LeftButtonDown())
|
||||
|
||||
@@ -22,10 +22,9 @@ namespace Barotrauma
|
||||
public GUIScrollBar ScrollBar { get; private set; }
|
||||
public GUIFrame Content { get; private set; }
|
||||
|
||||
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
|
||||
private int totalSize;
|
||||
|
||||
private int spacing;
|
||||
|
||||
private bool childrenNeedsRecalculation;
|
||||
private bool scrollBarNeedsRecalculation;
|
||||
|
||||
@@ -95,11 +94,7 @@ namespace Barotrauma
|
||||
get { return totalSize; }
|
||||
}
|
||||
|
||||
public int Spacing
|
||||
{
|
||||
get { return spacing; }
|
||||
set { spacing = value; }
|
||||
}
|
||||
public int Spacing { get; set; }
|
||||
|
||||
public override Color Color
|
||||
{
|
||||
@@ -244,37 +239,37 @@ namespace Barotrauma
|
||||
{
|
||||
if (ScrollBar.IsHorizontal)
|
||||
{
|
||||
if (y + child.Rect.Height + spacing > Content.Rect.Height)
|
||||
if (y + child.Rect.Height + Spacing > Content.Rect.Height)
|
||||
{
|
||||
y = 0;
|
||||
x += child.Rect.Width + spacing;
|
||||
x += child.Rect.Width + Spacing;
|
||||
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
|
||||
{
|
||||
child.RectTransform.AbsoluteOffset = new Point(x, y);
|
||||
}
|
||||
y += child.Rect.Height + spacing;
|
||||
y += child.Rect.Height + Spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
y += child.Rect.Height + spacing;
|
||||
y += child.Rect.Height + Spacing;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x + child.Rect.Width + spacing > Content.Rect.Width)
|
||||
if (x + child.Rect.Width + Spacing > Content.Rect.Width)
|
||||
{
|
||||
x = 0;
|
||||
y += child.Rect.Height + spacing;
|
||||
y += child.Rect.Height + Spacing;
|
||||
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
|
||||
{
|
||||
child.RectTransform.AbsoluteOffset = new Point(x, y);
|
||||
}
|
||||
x += child.Rect.Width + spacing;
|
||||
x += child.Rect.Width + Spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += child.Rect.Width + spacing;
|
||||
x += child.Rect.Width + Spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,11 +277,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (ScrollBar.IsHorizontal)
|
||||
{
|
||||
x += child.Rect.Width + spacing;
|
||||
x += child.Rect.Width + Spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
y += child.Rect.Height + spacing;
|
||||
y += child.Rect.Height + Spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,10 +322,23 @@ namespace Barotrauma
|
||||
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
if (!childVisible.ContainsKey(child)) { childVisible[child] = child.Visible; }
|
||||
if (childVisible[child] != child.Visible)
|
||||
{
|
||||
childVisible[child] = child.Visible;
|
||||
childrenNeedsRecalculation = true;
|
||||
scrollBarNeedsRecalculation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (childrenNeedsRecalculation)
|
||||
{
|
||||
RecalculateChildren();
|
||||
childVisible.Clear();
|
||||
}
|
||||
|
||||
UpdateOrder = order;
|
||||
@@ -511,30 +519,30 @@ namespace Barotrauma
|
||||
{
|
||||
if (ScrollBar.IsHorizontal)
|
||||
{
|
||||
if (pos + child.Rect.Height + spacing > Content.Rect.Height)
|
||||
if (pos + child.Rect.Height + Spacing > Content.Rect.Height)
|
||||
{
|
||||
pos = 0;
|
||||
totalSize += child.Rect.Width + spacing;
|
||||
totalSize += child.Rect.Width + Spacing;
|
||||
}
|
||||
pos += child.Rect.Height + spacing;
|
||||
pos += child.Rect.Height + Spacing;
|
||||
|
||||
if (child == children.Last())
|
||||
{
|
||||
totalSize += child.Rect.Width + spacing;
|
||||
totalSize += child.Rect.Width + Spacing;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos + child.Rect.Width + spacing > Content.Rect.Width)
|
||||
if (pos + child.Rect.Width + Spacing > Content.Rect.Width)
|
||||
{
|
||||
pos = 0;
|
||||
totalSize += child.Rect.Height + spacing;
|
||||
totalSize += child.Rect.Height + Spacing;
|
||||
}
|
||||
pos += child.Rect.Width + spacing;
|
||||
pos += child.Rect.Width + Spacing;
|
||||
|
||||
if (child == children.Last())
|
||||
{
|
||||
totalSize += child.Rect.Height + spacing;
|
||||
totalSize += child.Rect.Height + Spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -545,7 +553,7 @@ namespace Barotrauma
|
||||
{
|
||||
totalSize += (ScrollBar.IsHorizontal) ? child.Rect.Width : child.Rect.Height;
|
||||
}
|
||||
totalSize += Content.CountChildren * spacing;
|
||||
totalSize += Content.CountChildren * Spacing;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,7 +56,21 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Visible) return;
|
||||
|
||||
if (ProgressGetter != null) BarSize = ProgressGetter();
|
||||
if (ProgressGetter != null)
|
||||
{
|
||||
float newSize = MathHelper.Clamp(ProgressGetter(), 0.0f, 1.0f);
|
||||
if (!MathUtils.IsValid(newSize))
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GUIProgressBar.Draw:GetProgress",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
BarSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle sliderRect = new Rectangle(
|
||||
frame.Rect.X,
|
||||
|
||||
@@ -155,7 +155,8 @@ namespace Barotrauma
|
||||
string file = GetFontFilePath(element);
|
||||
uint size = GetFontSize(element);
|
||||
bool dynamicLoading = GetFontDynamicLoading(element);
|
||||
return new ScalableFont(file, size, graphicsDevice, dynamicLoading);
|
||||
bool isCJK = GetIsCJK(element);
|
||||
return new ScalableFont(file, size, graphicsDevice, dynamicLoading, isCJK);
|
||||
}
|
||||
|
||||
private uint GetFontSize(XElement element)
|
||||
@@ -200,6 +201,20 @@ namespace Barotrauma
|
||||
return element.GetAttributeBool("dynamicloading", false);
|
||||
}
|
||||
|
||||
private bool GetIsCJK(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
|
||||
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
|
||||
if (GameMain.Config.Language.ToLowerInvariant() == language)
|
||||
{
|
||||
return subElement.GetAttributeBool("iscjk", false);
|
||||
}
|
||||
}
|
||||
return element.GetAttributeBool("iscjk", false);
|
||||
}
|
||||
|
||||
public GUIComponentStyle GetComponentStyle(string name)
|
||||
{
|
||||
componentStyles.TryGetValue(name.ToLowerInvariant(), out GUIComponentStyle style);
|
||||
|
||||
@@ -204,8 +204,13 @@ namespace Barotrauma
|
||||
if (textColor.HasValue)
|
||||
{
|
||||
this.textColor = textColor.Value;
|
||||
}
|
||||
this.Font = font ?? GUI.Font;
|
||||
}
|
||||
|
||||
//if the text is in chinese/korean/japanese and we're not using a CJK-compatible font,
|
||||
//use the default CJK font as a fallback
|
||||
var selectedFont = font ?? GUI.Font;
|
||||
if (TextManager.IsCJK(text) && !selectedFont.IsCJK) { selectedFont = GUI.CJKFont; }
|
||||
this.Font = selectedFont;
|
||||
this.textAlignment = textAlignment;
|
||||
this.Wrap = wrap;
|
||||
this.Text = text ?? "";
|
||||
|
||||
@@ -190,7 +190,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) { return false; }
|
||||
SetCharacterOrder(null, order, null, Character.Controlled);
|
||||
foreach (var hull in Character.Controlled.GetVisibleHulls())
|
||||
var visibleHulls = new List<Hull>(Character.Controlled.GetVisibleHulls());
|
||||
foreach (var hull in visibleHulls)
|
||||
{
|
||||
HumanAIController.PropagateHullSafety(Character.Controlled, hull);
|
||||
HumanAIController.RefreshTargets(Character.Controlled, order, hull);
|
||||
|
||||
@@ -199,6 +199,7 @@ namespace Barotrauma.Tutorials
|
||||
SetHighlight(captain_navConsole.Item, true);
|
||||
SetHighlight(captain_sonar.Item, true);
|
||||
SetHighlight(captain_statusMonitor, true);
|
||||
captain_navConsole.UseAutoDocking = false;
|
||||
do
|
||||
{
|
||||
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
|
||||
@@ -221,6 +222,7 @@ namespace Barotrauma.Tutorials
|
||||
} while (captain_sonar.CurrentMode != Sonar.Mode.Active);
|
||||
do { yield return null; } while (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 4000f);
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
captain_navConsole.UseAutoDocking = true;
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
TriggerTutorialSegment(6); // Docking
|
||||
do
|
||||
|
||||
@@ -256,6 +256,7 @@ namespace Barotrauma.Tutorials
|
||||
GameMain.GameSession.CrewManager.AddCharacter(doctor);
|
||||
GameMain.GameSession.CrewManager.AddCharacter(patient1);
|
||||
GameMain.GameSession.CrewManager.ToggleCrewAreaOpen = true;
|
||||
patient1.CharacterHealth.UseHealthWindow = false;
|
||||
|
||||
yield return new WaitForSeconds(3.0f, false);
|
||||
patient1.AIController.Enabled = true;
|
||||
@@ -277,6 +278,7 @@ namespace Barotrauma.Tutorials
|
||||
RemoveCompletedObjective(segments[3]);
|
||||
SetHighlight(doctor_medBayCabinet.Item, true);
|
||||
SetDoorAccess(doctor_thirdDoor, doctor_thirdDoorLight, true);
|
||||
patient1.CharacterHealth.UseHealthWindow = true;
|
||||
|
||||
yield return new WaitForSeconds(2.0f, false);
|
||||
|
||||
|
||||
@@ -169,7 +169,9 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
|
||||
engineer_wire_1 = Item.ItemList.Find(i => i.HasTag("engineer_wire_1"));
|
||||
engineer_wire_1.SpriteColor = Color.Transparent;
|
||||
engineer_wire_2 = Item.ItemList.Find(i => i.HasTag("engineer_wire_2"));
|
||||
engineer_wire_2.SpriteColor = Color.Transparent;
|
||||
engineer_lamp_1 = Item.ItemList.Find(i => i.HasTag("engineer_lamp_1")).GetComponent<Powered>();
|
||||
engineer_lamp_2 = Item.ItemList.Find(i => i.HasTag("engineer_lamp_2")).GetComponent<Powered>();
|
||||
engineer_fourthDoor = Item.ItemList.Find(i => i.HasTag("engineer_fourthdoor")).GetComponent<Door>();
|
||||
@@ -416,6 +418,8 @@ namespace Barotrauma.Tutorials
|
||||
do { CheckJunctionBoxHighlights(); yield return null; } while (!engineer_submarineJunctionBox_1.IsFullCondition || !engineer_submarineJunctionBox_2.IsFullCondition || !engineer_submarineJunctionBox_3.IsFullCondition);
|
||||
CheckJunctionBoxHighlights();
|
||||
RemoveCompletedObjective(segments[4]);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
TriggerTutorialSegment(5); // Powerup reactor
|
||||
SetHighlight(engineer_submarineReactor.Item, true);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineReactor.Item, engineer_reactorIcon, engineer_reactorIconColor);
|
||||
@@ -425,6 +429,8 @@ namespace Barotrauma.Tutorials
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Complete"), ChatMessageType.Radio, null);
|
||||
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
|
||||
CoroutineManager.StartCoroutine(TutorialCompleted());
|
||||
}
|
||||
|
||||
@@ -472,17 +478,31 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
private void CheckGhostWires()
|
||||
{
|
||||
if (engineer_wire_1 != null && engineer_lamp_1.Voltage > engineer_lamp_1.MinVoltage)
|
||||
Color wireColor =
|
||||
Color.Orange *
|
||||
MathHelper.Lerp(0.25f, 0.75f, (float)(Math.Sin((Timing.TotalTime * 4.0f)) + 1.0f) / 2.0f);
|
||||
|
||||
if (engineer_wire_1 != null)
|
||||
{
|
||||
engineer_wire_1.Remove();
|
||||
engineer_wire_1 = null;
|
||||
engineer_wire_1.SpriteColor = wireColor;
|
||||
if (engineer_lamp_1.Voltage > engineer_lamp_1.MinVoltage)
|
||||
{
|
||||
engineer_wire_1.Remove();
|
||||
engineer_wire_1 = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (engineer_wire_2 != null && engineer_lamp_2.Voltage > engineer_lamp_2.MinVoltage)
|
||||
|
||||
if (engineer_wire_2 != null)
|
||||
{
|
||||
engineer_wire_2.Remove();
|
||||
engineer_wire_2 = null;
|
||||
engineer_wire_2.SpriteColor = wireColor;
|
||||
if (engineer_lamp_2.Voltage > engineer_lamp_2.MinVoltage)
|
||||
{
|
||||
engineer_wire_2.Remove();
|
||||
engineer_wire_2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void HandleJunctionBoxWiringHighlights()
|
||||
|
||||
@@ -526,6 +526,8 @@ namespace Barotrauma.Tutorials
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_weldIcon, mechanic_repairIconColor);
|
||||
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_2));
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Use)); // Repairing machinery (pump)
|
||||
SetHighlight(mechanic_brokenPump.Item, true);
|
||||
mechanic_brokenPump.CanBeSelected = true;
|
||||
|
||||
@@ -373,7 +373,7 @@ namespace Barotrauma.Tutorials
|
||||
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all five harpons loaded
|
||||
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, false);
|
||||
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, true);
|
||||
|
||||
@@ -113,8 +113,8 @@ namespace Barotrauma
|
||||
var tickBox = new GUITickBox(new RectTransform(tickBoxScale, contentPackageList.Content.RectTransform, scaleBasis: ScaleBasis.BothHeight), contentPackage.Name)
|
||||
{
|
||||
UserData = contentPackage,
|
||||
OnSelected = SelectContentPackage,
|
||||
Selected = SelectedContentPackages.Contains(contentPackage)
|
||||
Selected = SelectedContentPackages.Contains(contentPackage),
|
||||
OnSelected = SelectContentPackage
|
||||
};
|
||||
if (contentPackage.CorePackage)
|
||||
{
|
||||
@@ -153,11 +153,6 @@ namespace Barotrauma
|
||||
UnsavedSettings = true;
|
||||
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
|
||||
//change fonts to the default font of the new language to make sure
|
||||
//they can be displayed when for example changing from English to Chinese
|
||||
var defaultFont = GUI.Style.LoadCurrentDefaultFont();
|
||||
msgBox.Header.Font = defaultFont;
|
||||
msgBox.Text.Font = defaultFont;
|
||||
|
||||
return true;
|
||||
};
|
||||
@@ -445,17 +440,11 @@ namespace Barotrauma
|
||||
};
|
||||
voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll);
|
||||
|
||||
var leftTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.28f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
|
||||
{ RelativeOffset = new Vector2(0.02f, 0.32f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
var centerTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
|
||||
{ RelativeOffset = new Vector2(0.3f, 0.32f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
var rightTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopRight)
|
||||
var tickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.28f, 0.15f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
|
||||
{ RelativeOffset = new Vector2(0.02f, 0.32f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
|
||||
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, leftTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost"));
|
||||
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, tickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost"));
|
||||
muteOnFocusLostBox.Selected = MuteOnFocusLost;
|
||||
muteOnFocusLostBox.ToolTip = TextManager.Get("MuteOnFocusLostToolTip");
|
||||
muteOnFocusLostBox.OnSelected = (tickBox) =>
|
||||
@@ -465,7 +454,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
GUITickBox dynamicRangeCompressionTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, centerTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DynamicRangeCompression"));
|
||||
GUITickBox dynamicRangeCompressionTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, tickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DynamicRangeCompression"));
|
||||
dynamicRangeCompressionTickBox.Selected = DynamicRangeCompressionEnabled;
|
||||
dynamicRangeCompressionTickBox.ToolTip = TextManager.Get("DynamicRangeCompressionToolTip");
|
||||
dynamicRangeCompressionTickBox.OnSelected = (tickBox) =>
|
||||
@@ -475,7 +464,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
GUITickBox voipAttenuationTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, rightTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("VoipAttenuation"));
|
||||
GUITickBox voipAttenuationTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, tickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("VoipAttenuation"));
|
||||
voipAttenuationTickBox.Selected = VoipAttenuationEnabled;
|
||||
voipAttenuationTickBox.ToolTip = TextManager.Get("VoipAttenuationToolTip");
|
||||
voipAttenuationTickBox.OnSelected = (tickBox) =>
|
||||
@@ -485,8 +474,8 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
var voipSettings = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.4f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
|
||||
{ RelativeOffset = new Vector2(0.0f, 0.38f) })
|
||||
var voipSettings = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.35f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
|
||||
{ RelativeOffset = new Vector2(0.0f, 0.47f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), voipSettings.RectTransform), TextManager.Get("VoiceChat"));
|
||||
@@ -631,18 +620,21 @@ namespace Barotrauma
|
||||
var dbMeter = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.25f), voiceActivityGroup.RectTransform), 0.0f, Color.Lime);
|
||||
dbMeter.ProgressGetter = () =>
|
||||
{
|
||||
if (VoipCapture.Instance == null) return 0.0f;
|
||||
if (VoipCapture.Instance == null) { return 0.0f; }
|
||||
dbMeter.Color = VoipCapture.Instance.LastdB > NoiseGateThreshold ? Color.Lime : Color.Orange; //TODO: i'm a filthy hack
|
||||
return ((float)VoipCapture.Instance.LastdB + 100.0f) / 100.0f;
|
||||
|
||||
float scrollVal = double.IsNegativeInfinity(VoipCapture.Instance.LastdB) ? 0.0f : ((float)VoipCapture.Instance.LastdB + 100.0f) / 100.0f;
|
||||
return scrollVal * scrollVal;
|
||||
};
|
||||
var noiseGateSlider = new GUIScrollBar(new RectTransform(Vector2.One, dbMeter.RectTransform, Anchor.Center), color: Color.White, barSize: 0.03f);
|
||||
noiseGateSlider.Frame.Visible = false;
|
||||
noiseGateSlider.Step = 0.01f;
|
||||
noiseGateSlider.Range = new Vector2(-100.0f, 0.0f);
|
||||
noiseGateSlider.BarScrollValue = NoiseGateThreshold;
|
||||
noiseGateSlider.BarScroll = MathUtils.InverseLerp(-1.0f, 0.0f, NoiseGateThreshold);
|
||||
noiseGateSlider.BarScroll *= noiseGateSlider.BarScroll;
|
||||
noiseGateSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||
{
|
||||
NoiseGateThreshold = scrollBar.BarScrollValue;
|
||||
NoiseGateThreshold = MathHelper.Lerp(-100.0f, 0.0f, (float)Math.Sqrt(scrollBar.BarScroll));
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
};
|
||||
@@ -1018,6 +1010,7 @@ namespace Barotrauma
|
||||
SelectedContentPackages.Remove(contentPackage);
|
||||
}
|
||||
}
|
||||
if (contentPackage.GetFilesOfType(ContentType.Submarine).Any()) { Submarine.RefreshSavedSubs(); }
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ namespace Barotrauma
|
||||
|
||||
public override void RemoveItem(Item item)
|
||||
{
|
||||
if (!Items.Contains(item)) { return; }
|
||||
base.RemoveItem(item);
|
||||
CreateSlots();
|
||||
}
|
||||
@@ -175,7 +176,12 @@ namespace Barotrauma
|
||||
|
||||
AssignQuickUseNumKeys();
|
||||
|
||||
highlightedSubInventorySlots.Clear();
|
||||
highlightedSubInventorySlots.RemoveWhere(s => s.Inventory.OpenState <= 0.0f);
|
||||
foreach (var subSlot in highlightedSubInventorySlots)
|
||||
{
|
||||
subSlot.Slot = slots[subSlot.SlotIndex];
|
||||
}
|
||||
//highlightedSubInventorySlots.Clear();
|
||||
|
||||
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
CalculateBackgroundFrame();
|
||||
@@ -469,6 +475,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
List<SlotReference> hideSubInventories = new List<SlotReference>();
|
||||
highlightedSubInventorySlots.RemoveWhere(s => s.SlotIndex < 0 || s.SlotIndex >= Items.Length || Items[s.SlotIndex] == null);
|
||||
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||
{
|
||||
if (highlightedSubInventorySlot.ParentInventory == this)
|
||||
@@ -646,7 +653,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
slotRef.Inventory.OpenState = isEquippedSubInventory ? 1f : 0f; // Reset animation when initially equipped
|
||||
if (isEquippedSubInventory)
|
||||
{
|
||||
slotRef.Inventory.OpenState = 1.0f; // Reset animation when initially equipped
|
||||
}
|
||||
|
||||
highlightedSubInventorySlots.Add(slotRef);
|
||||
slotRef.Inventory.HideTimer = 1f;
|
||||
|
||||
@@ -146,14 +146,24 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (item.body == null)
|
||||
{
|
||||
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
|
||||
if (item.Submarine != null) transformedItemPos += item.Submarine.DrawPosition;
|
||||
transformedItemPos = transformedItemPos + ItemPos * item.Scale;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
transformedItemPos.X += item.Rect.Width;
|
||||
transformedItemInterval.X = -transformedItemInterval.X;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
transformedItemPos.Y = -transformedItemPos.Y;
|
||||
transformedItemPos.Y -= item.Rect.Height;
|
||||
transformedItemInterval.Y = -transformedItemInterval.Y;
|
||||
}
|
||||
transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
|
||||
if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; }
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
|
||||
if (item.body.Dir == -1.0f)
|
||||
{
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
@@ -169,6 +179,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
Vector2 currentItemPos = transformedItemPos;
|
||||
|
||||
SpriteEffects spriteEffects = SpriteEffects.None;
|
||||
if ((item.body != null && item.body.Dir == -1) || item.FlippedX) { spriteEffects |= SpriteEffects.FlipHorizontally; }
|
||||
if (item.FlippedY) { spriteEffects |= SpriteEffects.FlipVertically; }
|
||||
|
||||
int i = 0;
|
||||
foreach (Item containedItem in Inventory.Items)
|
||||
{
|
||||
@@ -192,7 +206,7 @@ namespace Barotrauma.Items.Components
|
||||
containedItem.GetSpriteColor(),
|
||||
-currentRotation,
|
||||
containedItem.Scale,
|
||||
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None,
|
||||
spriteEffects,
|
||||
depth: ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth);
|
||||
|
||||
foreach (ItemContainer ic in containedItem.GetComponents<ItemContainer>())
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -72,5 +73,10 @@ namespace Barotrauma.Items.Components
|
||||
GameMain.Client.ChatBox.ToggleOpen = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
state = msg.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Barotrauma.Items.Components
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
//targetForce can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(targetForce / 10.0f));
|
||||
msg.WriteRangedInteger((int)(targetForce / 10.0f), -10, 10);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
|
||||
@@ -44,6 +44,16 @@ namespace Barotrauma.Items.Components
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
|
||||
itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform))
|
||||
{
|
||||
OnSelected = (GUIComponent component, object userdata) =>
|
||||
{
|
||||
selectedItem = userdata as FabricationRecipe;
|
||||
if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); }
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var filterArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), paddedFrame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
@@ -58,16 +68,6 @@ namespace Barotrauma.Items.Components
|
||||
OnClicked = (btn, userdata) => { ClearFilter(); itemFilterBox.Flash(Color.White); return true; }
|
||||
};
|
||||
|
||||
itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform))
|
||||
{
|
||||
OnSelected = (GUIComponent component, object userdata) =>
|
||||
{
|
||||
selectedItem = userdata as FabricationRecipe;
|
||||
if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); }
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.15f), paddedFrame.RectTransform), style: null);
|
||||
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay, null)
|
||||
{
|
||||
@@ -462,7 +462,7 @@ namespace Barotrauma.Items.Components
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
int itemIndex = pendingFabricatedItem == null ? -1 : fabricationRecipes.IndexOf(pendingFabricatedItem);
|
||||
msg.WriteRangedIntegerDeprecated(-1, fabricationRecipes.Count - 1, itemIndex);
|
||||
msg.WriteRangedInteger(itemIndex, -1, fabricationRecipes.Count - 1);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Barotrauma.Items.Components
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(flowPercentage / 10.0f));
|
||||
msg.WriteRangedInteger((int)(flowPercentage / 10.0f), -10, 10);
|
||||
msg.Write(IsActive);
|
||||
}
|
||||
|
||||
|
||||
@@ -451,7 +451,10 @@ namespace Barotrauma.Items.Components
|
||||
if (PlayerInput.KeyDown(InputType.Right)) input.X += 1.0f;
|
||||
if (PlayerInput.KeyDown(InputType.Up)) input.Y += 1.0f;
|
||||
if (PlayerInput.KeyDown(InputType.Down)) input.Y += -1.0f;
|
||||
if (PlayerInput.KeyDown(InputType.Run)) rate = 200.0f;
|
||||
if (PlayerInput.KeyDown(InputType.Run))
|
||||
rate = 200.0f;
|
||||
else if (PlayerInput.KeyDown(InputType.Crouch))
|
||||
rate = 20.0f;
|
||||
|
||||
rate *= deltaTime;
|
||||
input.X *= rate;
|
||||
|
||||
@@ -73,11 +73,18 @@ namespace Barotrauma.Items.Components
|
||||
set { maintainPosTickBox.Selected = value; }
|
||||
}
|
||||
|
||||
private bool dockingModeEnabled;
|
||||
public bool DockingModeEnabled
|
||||
{
|
||||
get { return UseAutoDocking && dockingModeEnabled; }
|
||||
set { dockingModeEnabled = value; }
|
||||
}
|
||||
|
||||
public bool UseAutoDocking
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
} = true;
|
||||
|
||||
public List<DockingPort> DockingSources = new List<DockingPort>();
|
||||
public DockingPort ActiveDockingSource, DockingTarget;
|
||||
@@ -726,6 +733,8 @@ namespace Barotrauma.Items.Components
|
||||
inputCumulation = 0;
|
||||
keyboardInput = Vector2.Zero;
|
||||
}
|
||||
|
||||
if (!UseAutoDocking) { return; }
|
||||
|
||||
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
|
||||
DockingModeEnabled = false;
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
|
||||
msg.WriteRangedInteger((int)(rechargeSpeed / MaxRechargeSpeed * 10), 0, 10);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
@@ -140,7 +140,11 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
RechargeSpeed = msg.ReadRangedInteger(0, 10) / 10.0f * maxRechargeSpeed;
|
||||
float rechargeRate = msg.ReadRangedInteger(0, 10) / 10.0f;
|
||||
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
|
||||
#if CLIENT
|
||||
rechargeSpeedSlider.BarScroll = rechargeRate;
|
||||
#endif
|
||||
Charge = msg.ReadRangedSingle(0.0f, 1.0f, 8) * capacity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,13 +65,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
|
||||
partial void UseProjSpecific(float deltaTime)
|
||||
partial void UseProjSpecific(float deltaTime, Vector2 raystart)
|
||||
{
|
||||
if (ParticleEmitter != null)
|
||||
{
|
||||
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
ParticleEmitter.Emit(
|
||||
deltaTime, item.WorldPosition + TransformedBarrelPos,
|
||||
deltaTime, ConvertUnits.ToDisplayUnits(raystart),
|
||||
item.CurrentHull, particleAngle, ParticleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Collections.Generic;
|
||||
@@ -25,6 +26,8 @@ namespace Barotrauma.Items.Components
|
||||
//the corresponding particle emitter is active when the condition is within this range
|
||||
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||
|
||||
private SoundChannel repairSoundChannel;
|
||||
|
||||
private string repairButtonText, repairingText;
|
||||
private string sabotageButtonText, sabotagingText;
|
||||
|
||||
@@ -140,6 +143,19 @@ namespace Barotrauma.Items.Components
|
||||
particleEmitters[i].Emit(deltaTime, item.WorldPosition, item.CurrentHull);
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentFixer != null && CurrentFixer.SelectedConstruction == item)
|
||||
{
|
||||
if (repairSoundChannel == null || !repairSoundChannel.IsPlaying)
|
||||
{
|
||||
repairSoundChannel = SoundPlayer.PlaySound("repair", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
repairSoundChannel?.FadeOutAndDispose();
|
||||
repairSoundChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
@@ -177,20 +193,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
deteriorationTimer = msg.ReadSingle();
|
||||
deteriorateAlwaysResetTimer = msg.ReadSingle();
|
||||
DeteriorateAlways = msg.ReadBoolean();
|
||||
CurrentFixer = msg.ReadBoolean() ? Character.Controlled : null;
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||
{
|
||||
if (GameMain.DebugDraw && Character.Controlled?.FocusedItem == item)
|
||||
@@ -213,5 +215,25 @@ namespace Barotrauma.Items.Components
|
||||
Color.Orange);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
repairSoundChannel?.FadeOutAndDispose();
|
||||
repairSoundChannel = null;
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
deteriorationTimer = msg.ReadSingle();
|
||||
deteriorateAlwaysResetTimer = msg.ReadSingle();
|
||||
DeteriorateAlways = msg.ReadBoolean();
|
||||
CurrentFixer = msg.ReadBoolean() ? Character.Controlled : null;
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -12,6 +13,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
public static Wire HighlightedWire;
|
||||
|
||||
private SoundChannel rewireSoundChannel;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
if (GuiFrame == null) return;
|
||||
@@ -20,7 +23,37 @@ namespace Barotrauma.Items.Components
|
||||
UserData = this
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
foreach (Wire wire in DisconnectedWires)
|
||||
{
|
||||
if (Rand.Range(0.0f, 500.0f) < 1.0f)
|
||||
{
|
||||
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
Vector2 baseVel = new Vector2(0.0f, -100.0f);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
|
||||
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
|
||||
if (particle != null) { particle.Size *= Rand.Range(0.5f, 1.0f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (user != null && user.SelectedConstruction == item && HasRequiredItems(user, addMessage: false))
|
||||
{
|
||||
if (rewireSoundChannel == null || !rewireSoundChannel.IsPlaying)
|
||||
{
|
||||
rewireSoundChannel = SoundPlayer.PlaySound("rewire", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rewireSoundChannel?.FadeOutAndDispose();
|
||||
rewireSoundChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) return;
|
||||
|
||||
@@ -155,8 +155,8 @@ namespace Barotrauma
|
||||
public class SlotReference
|
||||
{
|
||||
public readonly Inventory ParentInventory;
|
||||
public readonly InventorySlot Slot;
|
||||
public readonly int SlotIndex;
|
||||
public InventorySlot Slot;
|
||||
|
||||
public Inventory Inventory;
|
||||
|
||||
@@ -741,17 +741,37 @@ namespace Barotrauma
|
||||
{
|
||||
Inventory selectedInventory = selectedSlot.ParentInventory;
|
||||
int slotIndex = selectedSlot.SlotIndex;
|
||||
if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
|
||||
|
||||
//if attempting to drop into an invalid slot in the same inventory, try to move to the correct slot
|
||||
if (selectedInventory.Items[slotIndex] == null &&
|
||||
selectedInventory == Character.Controlled.Inventory &&
|
||||
!draggingItem.AllowedSlots.Any(a => a.HasFlag(Character.Controlled.Inventory.SlotTypes[slotIndex])) &&
|
||||
selectedInventory.TryPutItem(draggingItem, Character.Controlled, draggingItem.AllowedSlots))
|
||||
{
|
||||
if (selectedInventory.slots != null) selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
|
||||
if (selectedInventory.slots != null)
|
||||
{
|
||||
for (int i = 0; i < selectedInventory.slots.Length; i++)
|
||||
{
|
||||
if (selectedInventory.Items[i] == draggingItem)
|
||||
{
|
||||
selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
|
||||
}
|
||||
}
|
||||
selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
|
||||
}
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
else if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
|
||||
{
|
||||
if (selectedInventory.slots != null) { selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f); }
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selectedInventory.slots != null) selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
|
||||
if (selectedInventory.slots != null){ selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f); }
|
||||
GUI.PlayUISound(GUISoundType.PickItemFail);
|
||||
}
|
||||
selectedInventory.HideTimer = 1.0f;
|
||||
selectedInventory.HideTimer = 2.0f;
|
||||
if (selectedSlot.ParentInventory?.Owner is Item parentItem && parentItem.ParentInventory != null)
|
||||
{
|
||||
for (int i = 0; i < parentItem.ParentInventory.capacity; i++)
|
||||
@@ -960,7 +980,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Bottom - 8, rect.Width, 8), Color.Black * 0.8f, true);
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(rect.X, rect.Bottom - 8, (int)(rect.Width * item.Condition / item.MaxCondition), 8),
|
||||
new Rectangle(rect.X, rect.Bottom - 8, (int)(rect.Width * (item.Condition / item.MaxCondition)), 8),
|
||||
Color.Lerp(Color.Red, Color.Green, item.Condition / item.MaxCondition) * 0.8f, true);
|
||||
}
|
||||
|
||||
@@ -1080,9 +1100,9 @@ namespace Barotrauma
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
receivedItemIDs = new ushort[capacity];
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
byte itemCount = msg.ReadByte();
|
||||
receivedItemIDs = new ushort[itemCount];
|
||||
for (int i = 0; i < itemCount; i++)
|
||||
{
|
||||
receivedItemIDs[i] = msg.ReadUInt16();
|
||||
}
|
||||
|
||||
@@ -930,17 +930,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
|
||||
msg.WriteRangedInteger((int)eventType, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
switch (eventType)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
int componentIndex = (int)extraData[1];
|
||||
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, componentIndex);
|
||||
msg.WriteRangedInteger(componentIndex, 0, components.Count - 1);
|
||||
(components[componentIndex] as IClientSerializable).ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
int containerIndex = (int)extraData[1];
|
||||
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, containerIndex);
|
||||
msg.WriteRangedInteger(containerIndex, 0, components.Count - 1);
|
||||
(components[containerIndex] as ItemContainer).Inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
@@ -1114,7 +1114,8 @@ namespace Barotrauma
|
||||
MapEntityPrefab.Find(itemName, itemIdentifier, showErrorMessages: false) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
string errorMsg = "Failed to spawn item (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null");
|
||||
string errorMsg = "Failed to spawn item, prefab not found (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null") + ")";
|
||||
errorMsg += "\n" + string.Join(", ", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name));
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:PrefabNotFound" + (itemName ?? "null") + (itemIdentifier ?? "null"),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Critical,
|
||||
errorMsg);
|
||||
|
||||
@@ -534,7 +534,7 @@ namespace Barotrauma
|
||||
msg.Write(FireSources.Count > 0);
|
||||
if (FireSources.Count > 0)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, 16, Math.Min(FireSources.Count, 16));
|
||||
msg.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
|
||||
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
|
||||
{
|
||||
var fireSource = FireSources[i];
|
||||
|
||||
@@ -45,7 +45,9 @@ namespace Barotrauma
|
||||
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
DebugConsole.ThrowError("Error when loading round sound (" + element + ") - file path not set");
|
||||
string errorMsg = "Error when loading round sound (" + element + ") - file path not set";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -69,7 +71,9 @@ namespace Barotrauma
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to load sound file \"" + filename + "\".", e);
|
||||
string errorMsg = "Failed to load sound file \"" + filename + "\".";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +84,12 @@ namespace Barotrauma.Networking
|
||||
font: GUI.SmallFont);
|
||||
|
||||
var reasonText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.0f), paddedPlayerFrame.RectTransform),
|
||||
TextManager.Get("BanReason") +
|
||||
TextManager.Get("BanReason") + " " +
|
||||
(string.IsNullOrEmpty(bannedPlayer.Reason) ? TextManager.Get("None") : ToolBox.LimitString(bannedPlayer.Reason, GUI.SmallFont, 170)),
|
||||
font: GUI.SmallFont, wrap: true)
|
||||
{
|
||||
ToolTip = bannedPlayer.Reason
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
return banFrame;
|
||||
@@ -100,34 +98,29 @@ namespace Barotrauma.Networking
|
||||
private bool RemoveBan(GUIButton button, object obj)
|
||||
{
|
||||
BannedPlayer banned = obj as BannedPlayer;
|
||||
if (banned == null) return false;
|
||||
if (banned == null) { return false; }
|
||||
|
||||
localRemovedBans.Add(banned.UniqueIdentifier);
|
||||
|
||||
RecreateBanFrame();
|
||||
|
||||
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Properties);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool RangeBan(GUIButton button, object obj)
|
||||
{
|
||||
BannedPlayer banned = obj as BannedPlayer;
|
||||
if (banned == null) return false;
|
||||
if (banned == null) { return false; }
|
||||
|
||||
localRangeBans.Add(banned.UniqueIdentifier);
|
||||
|
||||
RecreateBanFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CloseFrame(GUIButton button, object obj)
|
||||
{
|
||||
banFrame = null;
|
||||
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Properties);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void ClientAdminRead(IReadMessage incMsg)
|
||||
{
|
||||
bool hasPermission = incMsg.ReadBoolean();
|
||||
|
||||
@@ -460,13 +460,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorMessage = "Loading received submarine ''" + fileTransfer.FileName + "'' failed! {" + e.Message + "}";
|
||||
ErrorMessage = "Loading received submarine \"" + fileTransfer.FileName + "\" failed! {" + e.Message + "}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
ErrorMessage = "Decompressing received submarine file''" + fileTransfer.FilePath + "'' failed!";
|
||||
ErrorMessage = "Decompressing received submarine file \"" + fileTransfer.FilePath + "\" failed!";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -490,7 +490,7 @@ namespace Barotrauma.Networking
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
|
||||
ErrorMessage = "Parsing file ''" + fileTransfer.FilePath + "'' failed! The file may not be a valid submarine file.";
|
||||
ErrorMessage = "Parsing file \"" + fileTransfer.FilePath + "\" failed! The file may not be a valid submarine file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -396,15 +396,13 @@ namespace Barotrauma.Networking
|
||||
private bool connectCancelled;
|
||||
private void CancelConnect()
|
||||
{
|
||||
if (!(GameMain.ServerChildProcess?.HasExited??true))
|
||||
if (!(GameMain.ServerChildProcess?.HasExited ?? true))
|
||||
{
|
||||
GameMain.ServerChildProcess.Kill();
|
||||
GameMain.ServerChildProcess = null;
|
||||
}
|
||||
|
||||
connectCancelled = true;
|
||||
clientPeer?.Close();
|
||||
clientPeer = null;
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
// Before main looping starts, we loop here and wait for approval message
|
||||
@@ -554,14 +552,20 @@ namespace Barotrauma.Networking
|
||||
UpdateHUD(deltaTime);
|
||||
|
||||
base.Update(deltaTime);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
clientPeer?.Update(deltaTime);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Error while reading a message from server. {" + e + "}\n" + e.StackTrace;
|
||||
string errorMsg = "Error while reading a message from server. {" + e + "}. ";
|
||||
if (GameMain.Client == null) { errorMsg += "Client disposed."; }
|
||||
errorMsg += "\n" + e.StackTrace;
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
DebugConsole.ThrowError("Error while reading a message from server.", e);
|
||||
new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("MessageReadError", new string[2] { "[message]", "[targetsite]" }, new string[2] { e.Message, e.TargetSite.ToString() }));
|
||||
@@ -603,7 +607,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (IsServerOwner && connected && !connectCancelled)
|
||||
{
|
||||
if (GameMain.ServerChildProcess?.HasExited??true)
|
||||
if (GameMain.ServerChildProcess?.HasExited ?? true)
|
||||
{
|
||||
Disconnect();
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), TextManager.Get("ServerProcessClosed"));
|
||||
@@ -626,9 +630,34 @@ namespace Barotrauma.Networking
|
||||
ReadLobbyUpdate(inc);
|
||||
break;
|
||||
case ServerPacketHeader.UPDATE_INGAME:
|
||||
ReadIngameUpdate(inc);
|
||||
try
|
||||
{
|
||||
ReadIngameUpdate(inc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Error while reading an ingame update message from server. {" + e + "}\n" + e.StackTrace;
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
throw;
|
||||
}
|
||||
break;
|
||||
case ServerPacketHeader.VOICE:
|
||||
if (VoipClient == null)
|
||||
{
|
||||
string errorMsg = "Failed to read a voice packet from the server (VoipClient == null). ";
|
||||
if (GameMain.Client == null) { errorMsg += "Client disposed. "; }
|
||||
errorMsg += "\n" + Environment.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameClient.ReadDataMessage:VoipClientNull",
|
||||
GameMain.Client == null ? GameAnalyticsSDK.Net.EGAErrorSeverity.Error : GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
VoipClient.Read(inc);
|
||||
break;
|
||||
case ServerPacketHeader.QUERY_STARTGAME:
|
||||
@@ -728,7 +757,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
string[] splitMsg = disconnectMsg.Split('/');
|
||||
DisconnectReason disconnectReason = DisconnectReason.Unknown;
|
||||
if (splitMsg.Length > 0) Enum.TryParse(splitMsg[0], out disconnectReason);
|
||||
if (splitMsg.Length > 0) { Enum.TryParse(splitMsg[0], out disconnectReason); }
|
||||
|
||||
if (disconnectMsg == Lidgren.Network.NetConnection.NoResponseMessage)
|
||||
{
|
||||
@@ -737,6 +766,19 @@ namespace Barotrauma.Networking
|
||||
|
||||
DebugConsole.NewMessage("Received a disconnect message (" + disconnectMsg + ")");
|
||||
|
||||
if (disconnectReason != DisconnectReason.Banned &&
|
||||
disconnectReason != DisconnectReason.ServerShutdown &&
|
||||
disconnectReason != DisconnectReason.TooManyFailedLogins &&
|
||||
disconnectReason != DisconnectReason.NotOnWhitelist &&
|
||||
disconnectReason != DisconnectReason.MissingContentPackage &&
|
||||
disconnectReason != DisconnectReason.InvalidVersion)
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameClient.HandleDisconnectMessage",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Debug,
|
||||
"Client received a disconnect message. Reason: " + disconnectReason.ToString() + ", message: " + disconnectMsg);
|
||||
}
|
||||
|
||||
if (disconnectReason == DisconnectReason.ServerFull)
|
||||
{
|
||||
CoroutineManager.StopCoroutines("WaitForStartingInfo");
|
||||
@@ -1059,6 +1101,28 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (campaign == null)
|
||||
{
|
||||
//this shouldn't happen, TrySelectSub should stop the coroutine if the correct sub/shuttle cannot be found
|
||||
if (GameMain.NetLobbyScreen.SelectedSub == null ||
|
||||
GameMain.NetLobbyScreen.SelectedSub.Name != subName ||
|
||||
GameMain.NetLobbyScreen.SelectedSub.MD5Hash?.Hash != subHash)
|
||||
{
|
||||
string errorMsg = "Failed to select submarine \"" + subName + "\" (hash: " + subHash + ").";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
CoroutineManager.StartCoroutine(EndGame(""));
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
if (GameMain.NetLobbyScreen.SelectedShuttle == null ||
|
||||
GameMain.NetLobbyScreen.SelectedShuttle.Name != shuttleName ||
|
||||
GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash?.Hash != shuttleHash)
|
||||
{
|
||||
string errorMsg = "Failed to select shuttle \"" + shuttleName + "\" (hash: " + shuttleHash + ").";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
CoroutineManager.StartCoroutine(EndGame(""));
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
GameMain.GameSession = missionIndex < 0 ?
|
||||
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionType.None) :
|
||||
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionPrefab.List[missionIndex]);
|
||||
@@ -1252,7 +1316,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
existingClient.SetPermissions(permissions, permittedConsoleCommands);
|
||||
name = tc.Name;
|
||||
if (GameMain.NetLobbyScreen.CharacterNameBox != null)
|
||||
if (GameMain.NetLobbyScreen.CharacterNameBox != null &&
|
||||
!GameMain.NetLobbyScreen.CharacterNameBox.Selected)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CharacterNameBox.Text = name;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ namespace Barotrauma
|
||||
{
|
||||
public void CreateSettingsFrame(GUIComponent parent)
|
||||
{
|
||||
if (TextManager.ContainsTag("Karma.ResetKarmaBetweenRounds"))
|
||||
{
|
||||
CreateLabeledTickBox(parent, "ResetKarmaBetweenRounds");
|
||||
}
|
||||
|
||||
CreateLabeledSlider(parent, 0.0f, 40.0f, 1.0f, "KickBanThreshold");
|
||||
if (TextManager.ContainsTag("Karma.KicksBeforeBan"))
|
||||
{
|
||||
@@ -102,5 +107,14 @@ namespace Barotrauma
|
||||
};
|
||||
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, numInput);
|
||||
}
|
||||
|
||||
private void CreateLabeledTickBox(GUIComponent parent, string propertyName)
|
||||
{
|
||||
var tickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.1f), parent.RectTransform), TextManager.Get("Karma." + propertyName))
|
||||
{
|
||||
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip", returnNull: true) ?? ""
|
||||
};
|
||||
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, tickBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Barotrauma.Networking
|
||||
//find the first event that hasn't been sent in roundtriptime or at all
|
||||
eventLastSent.TryGetValue(events[i].ID, out float lastSent);
|
||||
|
||||
if (lastSent > Lidgren.Network.NetTime.Now - 50) //TODO: reimplement serverConnection.AverageRoundtripTime
|
||||
if (lastSent > Lidgren.Network.NetTime.Now - 0.2) //TODO: reimplement serverConnection.AverageRoundtripTime
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,11 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send "+initializationStep.ToString()+" message to host: " + result);
|
||||
}
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
@@ -207,7 +211,11 @@ namespace Barotrauma.Networking
|
||||
byte[] saltedPw = ServerSettings.SaltPassword(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password)), passwordSalt);
|
||||
outMsg.Write((byte)saltedPw.Length);
|
||||
outMsg.Write(saltedPw, 0, saltedPw.Length);
|
||||
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send " + initializationStep.ToString() + " message to host: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
@@ -247,7 +255,11 @@ namespace Barotrauma.Networking
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
NetSendResult result = netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to host: " + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
timeout = 20.0;
|
||||
timeout = NetworkConnection.TimeoutThreshold;
|
||||
heartbeatTimer = 1.0;
|
||||
|
||||
isActive = true;
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma.Networking
|
||||
if (!isActive) { return; }
|
||||
if (steamId != hostSteamId) { return; }
|
||||
|
||||
timeout = 20.0;
|
||||
timeout = NetworkConnection.TimeoutThreshold;
|
||||
|
||||
byte incByte = data[0];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Barotrauma.Networking
|
||||
private void OnAuthChange(ulong steamID, ulong ownerID, ClientAuthStatus status)
|
||||
{
|
||||
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);
|
||||
DebugConsole.NewMessage(steamID + " validation: " + status + ", " + (remotePeer != null));
|
||||
DebugConsole.Log(steamID + " validation: " + status + ", " + (remotePeer != null));
|
||||
|
||||
if (remotePeer == null) { return; }
|
||||
|
||||
@@ -106,7 +106,11 @@ namespace Barotrauma.Networking
|
||||
remotePeer.Authenticating = false;
|
||||
foreach (var msg in remotePeer.UnauthedMessages)
|
||||
{
|
||||
netClient.SendMessage(msg.Second, msg.First);
|
||||
NetSendResult result = netClient.SendMessage(msg.Second, msg.First);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send unauthed message to host: " + result);
|
||||
}
|
||||
}
|
||||
remotePeer.UnauthedMessages.Clear();
|
||||
}
|
||||
@@ -200,7 +204,11 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
netClient.SendMessage(outMsg, lidgrenDeliveryMethod);
|
||||
NetSendResult result = netClient.SendMessage(outMsg, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message from "+SteamManager.SteamIDUInt64ToString(remotePeer.SteamID)+" to host: " + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +352,11 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write(selfSteamID);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
|
||||
outMsg.Write(Name);
|
||||
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send initialization message to host: " + result);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -466,7 +478,11 @@ namespace Barotrauma.Networking
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
NetSendResult result = netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send own message to host: " + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,9 +218,9 @@ namespace Barotrauma.Steam
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("allowrespawn", serverSettings.AllowRespawn.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("traitors", serverSettings.TraitorsEnabled.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("gamestarted", GameMain.Client.GameStarted.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("gamemode", serverSettings.GameModeIdentifier);
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("gamemode", GameMain.NetLobbyScreen?.SelectedMode?.Identifier??"");
|
||||
|
||||
DebugConsole.NewMessage("Lobby updated!", Microsoft.Xna.Framework.Color.Lime);
|
||||
DebugConsole.Log("Lobby updated!");
|
||||
}
|
||||
|
||||
public static void LeaveLobby()
|
||||
@@ -770,6 +770,14 @@ namespace Barotrauma.Steam
|
||||
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem.Directory.FullName, MetadataFileName));
|
||||
string installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage));
|
||||
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
|
||||
|
||||
if (contentPackage == null && tempContentPackage.GameVersion <= new Version(0, 9, 1, 0))
|
||||
{
|
||||
//try finding the content package in the lega
|
||||
installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage, legacy: false));
|
||||
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
|
||||
}
|
||||
|
||||
if (tempContentPackage.GameVersion > new Version(0, 9, 1, 0))
|
||||
{
|
||||
itemEditor.Folder = Path.GetDirectoryName(installedContentPackagePath);
|
||||
@@ -784,6 +792,7 @@ namespace Barotrauma.Steam
|
||||
contentPackage.Path = newPath;
|
||||
itemEditor.Folder = newDir;
|
||||
if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); }
|
||||
if (File.Exists(newPath)) { File.Delete(newPath); }
|
||||
File.Move(installedContentPackagePath, newPath);
|
||||
//move all files inside the Mods folder
|
||||
foreach (ContentFile cf in contentPackage.Files)
|
||||
@@ -793,10 +802,12 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
string destinationPath = Path.Combine(newDir, cf.Path);
|
||||
if (!Directory.Exists(Path.GetDirectoryName(destinationPath))) { Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); }
|
||||
if (File.Exists(destinationPath)) { File.Delete(destinationPath); }
|
||||
File.Move(cf.Path, destinationPath);
|
||||
cf.Path = destinationPath;
|
||||
}
|
||||
}
|
||||
contentPackage.GameVersion = GameMain.Version;
|
||||
contentPackage.Save(contentPackage.Path);
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -1202,7 +1213,22 @@ namespace Barotrauma.Steam
|
||||
return false;
|
||||
}
|
||||
|
||||
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
|
||||
string metaDataPath = "";
|
||||
try
|
||||
{
|
||||
metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
string errorMessage = "Metadata file for the Workshop item \"" + item.Title +
|
||||
"\" not found. Could not combine path (" + (item.Directory.FullName ?? "directory name empty") + ").";
|
||||
DebugConsole.ThrowError(errorMessage);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CheckWorkshopItemEnabled:PathCombineException" + item.Title,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(metaDataPath))
|
||||
{
|
||||
DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
|
||||
@@ -1309,12 +1335,18 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
|
||||
public static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage)
|
||||
{
|
||||
return GetWorkshopItemContentPackagePath(contentPackage, legacy: contentPackage.GameVersion <= new Version(0, 9, 1, 0));
|
||||
}
|
||||
|
||||
private static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage, bool legacy)
|
||||
{
|
||||
string fileName = contentPackage.Name;
|
||||
string invalidChars = ToolBox.RemoveInvalidFileNameChars(fileName);
|
||||
return contentPackage.GameVersion > new Version(0, 9, 1, 0) ?
|
||||
Path.Combine("Mods", fileName, MetadataFileName) :
|
||||
Path.Combine("Data", "ContentPackages", fileName + ".xml"); //legacy support
|
||||
fileName = ToolBox.RemoveInvalidFileNameChars(fileName);
|
||||
|
||||
return legacy ?
|
||||
Path.Combine("Data", "ContentPackages", fileName + ".xml") :
|
||||
Path.Combine("Mods", fileName, MetadataFileName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace Barotrauma.Networking
|
||||
client.VoipSound = new VoipSound(GameMain.SoundManager, client.VoipQueue);
|
||||
}
|
||||
|
||||
if (client.Character != null && !client.Character.IsDead && client.Character.SpeechImpediment <= 100.0f)
|
||||
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
|
||||
{
|
||||
var messageType = ChatMessage.CanUseRadio(client.Character, out WifiComponent radio) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
||||
@@ -119,7 +119,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (client.VoipSound.CurrentAmplitude > 0.1f) //TODO: might need to tweak
|
||||
{
|
||||
if (client.Character != null)
|
||||
if (client.Character != null && !client.Character.Removed)
|
||||
{
|
||||
Vector3 clientPos = new Vector3(client.Character.WorldPosition.X, client.Character.WorldPosition.Y, 0.0f);
|
||||
Vector3 listenerPos = GameMain.SoundManager.ListenerPosition;
|
||||
|
||||
@@ -859,6 +859,9 @@ namespace Barotrauma
|
||||
|
||||
private void FillStoreItemList()
|
||||
{
|
||||
float prevStoreItemScroll = storeItemList.BarScroll;
|
||||
float prevMyItemScroll = myItemList.BarScroll;
|
||||
|
||||
int width = storeItemList.Rect.Width;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
|
||||
@@ -883,6 +886,9 @@ namespace Barotrauma
|
||||
|
||||
storeItemList.Content.RectTransform.SortChildren(
|
||||
(x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name));
|
||||
|
||||
storeItemList.BarScroll = prevStoreItemScroll;
|
||||
myItemList.BarScroll = prevMyItemScroll;
|
||||
}
|
||||
|
||||
private void FilterStoreItems(MapEntityCategory? category, string filter)
|
||||
@@ -904,7 +910,7 @@ namespace Barotrauma
|
||||
btn.Selected = (MapEntityCategory)btn.UserData == selectedItemCategory;
|
||||
}
|
||||
storeItemList.UpdateScrollBarSize();
|
||||
storeItemList.BarScroll = 0.0f;
|
||||
//storeItemList.BarScroll = 0.0f;
|
||||
}
|
||||
|
||||
public string GetMoney()
|
||||
|
||||
@@ -1216,7 +1216,7 @@ namespace Barotrauma
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash.Hash == sub.MD5Hash.Hash);
|
||||
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
|
||||
if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
|
||||
|
||||
if (matchingSub == null)
|
||||
@@ -1224,7 +1224,7 @@ namespace Barotrauma
|
||||
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
||||
frame.ToolTip = TextManager.Get("SubNotFound");
|
||||
}
|
||||
else if (matchingSub.MD5Hash.Hash != sub.MD5Hash.Hash)
|
||||
else if (matchingSub?.MD5Hash == null || matchingSub.MD5Hash?.Hash != sub.MD5Hash?.Hash)
|
||||
{
|
||||
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
||||
frame.ToolTip = TextManager.Get("SubDoesntMatch");
|
||||
@@ -1383,25 +1383,44 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) ClosePlayerFrame(btn, userdata); return true; }
|
||||
};
|
||||
|
||||
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .44f) : new Vector2(.24f, .24f);
|
||||
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .5f) : new Vector2(.24f, .24f);
|
||||
|
||||
var playerFrameInner = new GUIFrame(new RectTransform(frameSize, playerFrame.RectTransform, Anchor.Center));
|
||||
var paddedPlayerFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), playerFrameInner.RectTransform, Anchor.Center))
|
||||
var playerFrameInner = new GUIFrame(new RectTransform(frameSize, playerFrame.RectTransform, Anchor.Center) { MinSize = new Point(550, 0) });
|
||||
var paddedPlayerFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.88f), playerFrameInner.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
RelativeSpacing = 0.03f
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform),
|
||||
var headerContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var nameText = new GUITextBlock(new RectTransform(new Vector2(0.75f, 1.0f), headerContainer.RectTransform),
|
||||
text: selectedClient.Name, font: GUI.LargeFont);
|
||||
|
||||
//TODO: UI for client permission management
|
||||
if (selectedClient.SteamID != 0 && Steam.SteamManager.IsInitialized)
|
||||
{
|
||||
var viewSteamProfileButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), headerContainer.RectTransform, Anchor.TopCenter),
|
||||
TextManager.Get("ViewSteamProfile"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
};
|
||||
|
||||
GUITextBlock.AutoScaleAndNormalize(nameText, viewSteamProfileButton.TextBlock);
|
||||
|
||||
viewSteamProfileButton.OnClicked = (bt, userdata) =>
|
||||
{
|
||||
Steam.SteamManager.Instance.Overlay.OpenUrl("https://steamcommunity.com/profiles/" + selectedClient.SteamID.ToString());
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
if (GameMain.Client.HasPermission(ClientPermissions.ManagePermissions))
|
||||
{
|
||||
playerFrame.UserData = selectedClient;
|
||||
|
||||
//new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), selectedClient.Connection.RemoteEndPoint.Address.ToString());
|
||||
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paddedPlayerFrame.RectTransform),
|
||||
TextManager.Get("Rank"));
|
||||
var rankDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform),
|
||||
@@ -1441,16 +1460,45 @@ namespace Barotrauma
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("Permissions"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("PermittedConsoleCommands"));
|
||||
|
||||
var permissionLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("Permissions"));
|
||||
var consoleCommandLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("PermittedConsoleCommands"));
|
||||
GUITextBlock.AutoScaleAndNormalize(permissionLabel, consoleCommandLabel);
|
||||
|
||||
var permissionContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), paddedPlayerFrame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
var permissionsBox = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
|
||||
var listBoxContainerLeft = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
new GUITickBox(new RectTransform(new Vector2(0.15f, 0.15f), listBoxContainerLeft.RectTransform), TextManager.Get("all", fallBackTag: "clientpermission.all"))
|
||||
{
|
||||
Enabled = !myClient,
|
||||
OnSelected = (tickbox) =>
|
||||
{
|
||||
//reset rank to custom
|
||||
rankDropDown.SelectItem(null);
|
||||
|
||||
var client = playerFrame.UserData as Client;
|
||||
if (client == null) { return false; }
|
||||
|
||||
foreach (GUIComponent child in tickbox.Parent.GetChild<GUIListBox>().Content.Children)
|
||||
{
|
||||
var permissionTickBox = child as GUITickBox;
|
||||
permissionTickBox.Enabled = false;
|
||||
permissionTickBox.Selected = tickbox.Selected;
|
||||
permissionTickBox.Enabled = true;
|
||||
}
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var permissionsBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), listBoxContainerLeft.RectTransform))
|
||||
{
|
||||
UserData = selectedClient
|
||||
};
|
||||
@@ -1471,10 +1519,9 @@ namespace Barotrauma
|
||||
rankDropDown.SelectItem(null);
|
||||
|
||||
var client = playerFrame.UserData as Client;
|
||||
if (client == null) return false;
|
||||
if (client == null) { return false; }
|
||||
|
||||
var thisPermission = (ClientPermissions)tickBox.UserData;
|
||||
|
||||
if (tickBox.Selected)
|
||||
{
|
||||
client.GivePermission(thisPermission);
|
||||
@@ -1483,15 +1530,44 @@ namespace Barotrauma
|
||||
{
|
||||
client.RemovePermission(thisPermission);
|
||||
}
|
||||
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
|
||||
if (tickBox.Enabled)
|
||||
{
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var commandList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
|
||||
var listBoxContainerRight = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
new GUITickBox(new RectTransform(new Vector2(0.15f, 0.15f), listBoxContainerRight.RectTransform), TextManager.Get("all", fallBackTag: "clientpermission.all"))
|
||||
{
|
||||
Enabled = !myClient,
|
||||
OnSelected = (tickbox) =>
|
||||
{
|
||||
//reset rank to custom
|
||||
rankDropDown.SelectItem(null);
|
||||
|
||||
var client = playerFrame.UserData as Client;
|
||||
if (client == null) { return false; }
|
||||
|
||||
foreach (GUIComponent child in tickbox.Parent.GetChild<GUIListBox>().Content.Children)
|
||||
{
|
||||
var commandTickBox = child as GUITickBox;
|
||||
commandTickBox.Enabled = false;
|
||||
commandTickBox.Selected = tickbox.Selected;
|
||||
commandTickBox.Enabled = true;
|
||||
}
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var commandList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), listBoxContainerRight.RectTransform))
|
||||
{
|
||||
UserData = selectedClient
|
||||
};
|
||||
@@ -1522,37 +1598,23 @@ namespace Barotrauma
|
||||
{
|
||||
client.PermittedConsoleCommands.Add(selectedCommand);
|
||||
}
|
||||
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
if (tickBox.Enabled)
|
||||
{
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var buttonAreaUpper = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
var buttonAreaMiddle = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
var buttonAreaLower = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
|
||||
if (selectedClient.SteamID != 0 && Steam.SteamManager.IsInitialized)
|
||||
{
|
||||
var viewSteamProfileButton = new GUIButton(new RectTransform(new Vector2(0.8f, 1.0f), buttonAreaUpper.RectTransform, Anchor.TopCenter),
|
||||
TextManager.Get("ViewSteamProfile"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
};
|
||||
|
||||
viewSteamProfileButton.OnClicked = (bt, userdata) =>
|
||||
{
|
||||
Steam.SteamManager.Instance.Overlay.OpenUrl("https://steamcommunity.com/profiles/" + selectedClient.SteamID.ToString());
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
var buttonAreaTop = myClient ? null : new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
var buttonAreaLower = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
|
||||
if (!myClient)
|
||||
{
|
||||
if (GameMain.Client.HasPermission(ClientPermissions.Ban))
|
||||
{
|
||||
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaMiddle.RectTransform),
|
||||
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaTop.RectTransform),
|
||||
TextManager.Get("Ban"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
@@ -1560,7 +1622,7 @@ namespace Barotrauma
|
||||
banButton.OnClicked = (bt, userdata) => { BanPlayer(selectedClient); return true; };
|
||||
banButton.OnClicked += ClosePlayerFrame;
|
||||
|
||||
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaMiddle.RectTransform),
|
||||
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaTop.RectTransform),
|
||||
TextManager.Get("BanRange"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
@@ -1594,7 +1656,7 @@ namespace Barotrauma
|
||||
kickButton.OnClicked += ClosePlayerFrame;
|
||||
}
|
||||
|
||||
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaMiddle.RectTransform, Anchor.TopRight),
|
||||
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaTop.RectTransform, Anchor.TopRight),
|
||||
TextManager.Get("Mute"))
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
@@ -1982,24 +2044,34 @@ namespace Barotrauma
|
||||
|
||||
public bool TrySelectSub(string subName, string md5Hash, GUIListBox subList)
|
||||
{
|
||||
if (GameMain.Client == null) return false;
|
||||
if (GameMain.Client == null) { return false; }
|
||||
|
||||
//already downloading the selected sub file
|
||||
if (GameMain.Client.FileReceiver.ActiveTransfers.Any(t => t.FileName == subName + ".sub"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Submarine sub = subList.Content.Children
|
||||
.FirstOrDefault(c => c.UserData is Submarine s && s.Name == subName && s.MD5Hash?.Hash == md5Hash)?
|
||||
.UserData as Submarine;
|
||||
|
||||
Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName && m.MD5Hash.Hash == md5Hash);
|
||||
if (sub == null) sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName);
|
||||
|
||||
var matchingListSub = subList.Content.GetChildByUserData(sub);
|
||||
if (sub != null && subList.SelectedData as Submarine == sub)
|
||||
//matching sub found and already selected, all good
|
||||
if (sub != null && subList.SelectedData is Submarine selectedSub && selectedSub.MD5Hash?.Hash == md5Hash)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (matchingListSub != null)
|
||||
//sub not found, see if we have a sub with the same name
|
||||
if (sub == null)
|
||||
{
|
||||
sub = subList.Content.Children
|
||||
.FirstOrDefault(c => c.UserData is Submarine s && s.Name == subName)?
|
||||
.UserData as Submarine;
|
||||
}
|
||||
|
||||
//found a sub that at least has the same name, select it
|
||||
if (sub != null)
|
||||
{
|
||||
if (subList.Parent is GUIDropDown subDropDown)
|
||||
{
|
||||
@@ -2008,7 +2080,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
subList.OnSelected -= VotableClicked;
|
||||
subList.Select(subList.Content.GetChildIndex(matchingListSub), true);
|
||||
subList.Select(sub, force: true);
|
||||
subList.OnSelected += VotableClicked;
|
||||
}
|
||||
|
||||
@@ -2016,58 +2088,62 @@ namespace Barotrauma
|
||||
FailedSelectedSub = null;
|
||||
else
|
||||
FailedSelectedShuttle = null;
|
||||
|
||||
//hashes match, all good
|
||||
if (sub.MD5Hash?.Hash == md5Hash)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
//if we get to this point, a matching sub was not found or it has an incorrect MD5 hash
|
||||
|
||||
if (subList == SubList)
|
||||
FailedSelectedSub = new Pair<string, string>(subName, md5Hash);
|
||||
else
|
||||
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
|
||||
|
||||
string errorMsg = "";
|
||||
if (sub == null)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
|
||||
}
|
||||
else if (sub.MD5Hash?.Hash == null)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("SubLoadError", "[subname]", subName) + " ";
|
||||
subList.Content.GetChildByUserData(sub).GetChild<GUITextBox>().TextColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("SubDoesntMatchError", new string[3] { "[subname]" , "[myhash]", "[serverhash]" },
|
||||
new string[3] { sub.Name, sub.MD5Hash.ShortHash, Md5Hash.GetShortHash(md5Hash) }) + " ";
|
||||
}
|
||||
|
||||
if (sub == null || sub.MD5Hash.Hash != md5Hash)
|
||||
errorMsg += TextManager.Get("DownloadSubQuestion");
|
||||
|
||||
//already showing a message about the same sub
|
||||
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "request" + subName))
|
||||
{
|
||||
if (subList == SubList)
|
||||
FailedSelectedSub = new Pair<string, string>(subName, md5Hash);
|
||||
else
|
||||
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
|
||||
|
||||
string errorMsg = "";
|
||||
if (sub == null)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
|
||||
}
|
||||
else if (sub.MD5Hash.Hash == null)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("SubLoadError", "[subname]", subName) + " ";
|
||||
if (matchingListSub != null) matchingListSub.GetChild<GUITextBox>().TextColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("SubDoesntMatchError", new string[3] { "[subname]" , "[myhash]", "[serverhash]" },
|
||||
new string[3] { sub.Name, sub.MD5Hash.ShortHash, Md5Hash.GetShortHash(md5Hash) }) + " ";
|
||||
}
|
||||
|
||||
errorMsg += TextManager.Get("DownloadSubQuestion");
|
||||
|
||||
//already showing a message about the same sub
|
||||
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "request" + subName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var requestFileBox = new GUIMessageBox(TextManager.Get("DownloadSubLabel"), errorMsg,
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
|
||||
{
|
||||
UserData = "request" + subName
|
||||
};
|
||||
requestFileBox.Buttons[0].UserData = new string[] { subName, md5Hash };
|
||||
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
|
||||
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>
|
||||
{
|
||||
string[] fileInfo = (string[])userdata;
|
||||
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo[0], fileInfo[1]);
|
||||
return true;
|
||||
};
|
||||
requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
var requestFileBox = new GUIMessageBox(TextManager.Get("DownloadSubLabel"), errorMsg,
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
|
||||
{
|
||||
UserData = "request" + subName
|
||||
};
|
||||
requestFileBox.Buttons[0].UserData = new string[] { subName, md5Hash };
|
||||
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
|
||||
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>
|
||||
{
|
||||
string[] fileInfo = (string[])userdata;
|
||||
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo[0], fileInfo[1]);
|
||||
return true;
|
||||
};
|
||||
requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1297,13 +1297,13 @@ namespace Barotrauma
|
||||
|
||||
string modFolder = Path.GetDirectoryName(itemContentPackage.Path);
|
||||
string filePathRelativeToModFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, modFolder));
|
||||
string destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
|
||||
string destinationPath;
|
||||
|
||||
//file is not inside the mod folder, we need to move it
|
||||
if (filePathRelativeToModFolder.StartsWith("..") ||
|
||||
Path.GetPathRoot(Environment.CurrentDirectory) != Path.GetPathRoot(file))
|
||||
{
|
||||
string tryPath = destinationPath;
|
||||
destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
|
||||
//add a number to the filename if a file with the same name already exists
|
||||
i = 2;
|
||||
while (File.Exists(destinationPath))
|
||||
@@ -1317,10 +1317,14 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Copying the file \""+file+"\" to the mod folder failed.", e);
|
||||
DebugConsole.ThrowError("Copying the file \"" + file + "\" to the mod folder failed.", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
destinationPath = Path.Combine(modFolder, filePathRelativeToModFolder);
|
||||
}
|
||||
itemContentPackage.AddFile(destinationPath, ContentType.None);
|
||||
}
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Barotrauma
|
||||
"CrewExperienceHigh"
|
||||
};
|
||||
|
||||
private readonly Point defaultPreviewImageSize = new Point(512, 368);
|
||||
private readonly Point defaultPreviewImageSize = new Point(640, 368);
|
||||
|
||||
private Camera cam;
|
||||
|
||||
@@ -158,7 +158,26 @@ namespace Barotrauma
|
||||
|
||||
var button = new GUIButton(new RectTransform(new Vector2(0.07f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft), TextManager.Get("Back"))
|
||||
{
|
||||
OnClicked = GameMain.MainMenuScreen.ReturnToMainMenu
|
||||
OnClicked = (b, d) =>
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuQuitVerificationEditor"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
|
||||
{
|
||||
UserData = "verificationprompt"
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
|
||||
{
|
||||
GUIMessageBox.CloseAll();
|
||||
GameMain.MainMenuScreen.Select();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = (_, userdata) =>
|
||||
{
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
button = new GUIButton(new RectTransform(new Vector2(0.07f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.07f, 0.0f) }, TextManager.Get("OpenSubButton"))
|
||||
@@ -497,9 +516,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
|
||||
{
|
||||
var itemAssemblyPrefab = ep as ItemAssemblyPrefab;
|
||||
#if !DEBUG
|
||||
if (itemAssemblyPrefab != null && itemAssemblyPrefab.HideInMenus) { continue; }
|
||||
if (ep.HideInMenus) { continue; }
|
||||
#endif
|
||||
|
||||
bool legacy = ep.Category == MapEntityCategory.Legacy;
|
||||
@@ -548,7 +566,7 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
if (ep.Category == MapEntityCategory.ItemAssembly)
|
||||
if (ep is ItemAssemblyPrefab itemAssemblyPrefab)
|
||||
{
|
||||
new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.75f),
|
||||
paddedFrame.RectTransform, Anchor.TopCenter), onDraw: itemAssemblyPrefab.DrawIcon, onUpdate: null)
|
||||
@@ -2448,7 +2466,7 @@ namespace Barotrauma
|
||||
Matrix.CreateScale(new Vector3(scale, scale, 1)) *
|
||||
viewMatrix;
|
||||
|
||||
Sprite backgroundSprite = LevelGenerationParams.LevelParams.Find(l => l.BackgroundTopSprite != null).BackgroundTopSprite;
|
||||
/*Sprite backgroundSprite = LevelGenerationParams.LevelParams.Find(l => l.BackgroundTopSprite != null).BackgroundTopSprite;*/
|
||||
|
||||
using (RenderTarget2D rt = new RenderTarget2D(
|
||||
GameMain.Instance.GraphicsDevice,
|
||||
@@ -2457,14 +2475,14 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Instance.GraphicsDevice.SetRenderTarget(rt);
|
||||
|
||||
GameMain.Instance.GraphicsDevice.Clear(Color.Black);
|
||||
GameMain.Instance.GraphicsDevice.Clear(new Color(8, 13, 19));
|
||||
|
||||
if (backgroundSprite != null)
|
||||
/*if (backgroundSprite != null)
|
||||
{
|
||||
spriteBatch.Begin();
|
||||
backgroundSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(width, height), color: new Color(0.025f, 0.075f, 0.131f, 1.0f));
|
||||
spriteBatch.End();
|
||||
}
|
||||
}*/
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, transform);
|
||||
Submarine.Draw(spriteBatch, false);
|
||||
|
||||
@@ -484,12 +484,19 @@ namespace Barotrauma
|
||||
public static SoundChannel PlaySound(string soundTag, Vector2 position, float? volume = null, float? range = null, Hull hullGuess = null)
|
||||
{
|
||||
var sound = GetSound(soundTag);
|
||||
if (sound == null) return null;
|
||||
if (sound == null) { return null; }
|
||||
return PlaySound(sound, position, volume ?? sound.BaseGain, range ?? sound.BaseFar, hullGuess);
|
||||
}
|
||||
|
||||
public static SoundChannel PlaySound(Sound sound, Vector2 position, float? volume = null, float? range = null, Hull hullGuess = null)
|
||||
{
|
||||
if (sound == null)
|
||||
{
|
||||
string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
float far = range ?? sound.BaseFar;
|
||||
|
||||
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > far * far) return null;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Barotrauma
|
||||
break;
|
||||
case "sound":
|
||||
var sound = Submarine.LoadRoundSound(subElement);
|
||||
if (sound != null)
|
||||
if (sound?.Sound != null)
|
||||
{
|
||||
loopSound = subElement.GetAttributeBool("loop", false);
|
||||
if (subElement.Attribute("selectionmode") != null)
|
||||
|
||||
@@ -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.9.2.1")]
|
||||
[assembly: AssemblyFileVersion("0.9.2.1")]
|
||||
[assembly: AssemblyVersion("0.9.3.2")]
|
||||
[assembly: AssemblyFileVersion("0.9.3.2")]
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
<Compile Include="Source\Items\Components\Door.cs" />
|
||||
<Compile Include="Source\Items\Components\ItemComponent.cs" />
|
||||
<Compile Include="Source\Items\Components\ItemLabel.cs" />
|
||||
<Compile Include="Source\Items\Components\Machines\Controller.cs" />
|
||||
<Compile Include="Source\Items\Components\Machines\Deconstructor.cs" />
|
||||
<Compile Include="Source\Items\Components\Machines\Engine.cs" />
|
||||
<Compile Include="Source\Items\Components\Machines\Fabricator.cs" />
|
||||
|
||||
@@ -263,20 +263,20 @@ namespace Barotrauma
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 0);
|
||||
msg.WriteRangedInteger(0, 0, 3);
|
||||
Inventory.SharedWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Control:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 1);
|
||||
msg.WriteRangedInteger(1, 0, 3);
|
||||
Client owner = ((Client)extraData[1]);
|
||||
msg.Write(owner == null ? (byte)0 : owner.ID);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 2);
|
||||
msg.WriteRangedInteger(2, 0, 3);
|
||||
WriteStatus(msg);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateSkills:
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 3);
|
||||
msg.WriteRangedInteger(3, 0, 3);
|
||||
if (Info?.Job == null)
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
@@ -411,10 +411,10 @@ namespace Barotrauma
|
||||
msg.Write(IsDead);
|
||||
if (IsDead)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1, (int)CauseOfDeath.Type);
|
||||
msg.WriteRangedInteger((int)CauseOfDeath.Type, 0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1);
|
||||
if (CauseOfDeath.Type == CauseOfDeathType.Affliction)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(CauseOfDeath.Affliction));
|
||||
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(CauseOfDeath.Affliction), 0, AfflictionPrefab.List.Count - 1);
|
||||
}
|
||||
|
||||
if (AnimController?.LimbJoints == null)
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Traitor
|
||||
{
|
||||
public readonly Character Character;
|
||||
public Character TargetCharacter; //TODO: make a modular objective system (similar to crew missions) that allows for things OTHER than assasinations.
|
||||
|
||||
public Traitor(Character character)
|
||||
{
|
||||
Character = character;
|
||||
}
|
||||
|
||||
public void Greet(GameServer server, string codeWords, string codeResponse)
|
||||
{
|
||||
string greetingMessage = TextManager.GetWithVariable("TraitorStartMessage", "[targetname]", TargetCharacter.Name);
|
||||
string moreAgentsMessage = TextManager.GetWithVariables("TraitorMoreAgentsMessage",
|
||||
new string[2] { "[codewords]", "[coderesponse]" }, new string[2] { codeWords, codeResponse });
|
||||
|
||||
var greetingChatMsg = ChatMessage.Create(null, greetingMessage, ChatMessageType.Server, null);
|
||||
var moreAgentsChatMsg = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.Server, null);
|
||||
|
||||
var moreAgentsMsgBox = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.MessageBox, null);
|
||||
var greetingMsgBox = ChatMessage.Create(null, greetingMessage, ChatMessageType.MessageBox, null);
|
||||
|
||||
Client traitorClient = server.ConnectedClients.Find(c => c.Character == Character);
|
||||
GameMain.Server.SendDirectChatMessage(greetingChatMsg, traitorClient);
|
||||
GameMain.Server.SendDirectChatMessage(moreAgentsChatMsg, traitorClient);
|
||||
GameMain.Server.SendDirectChatMessage(greetingMsgBox, traitorClient);
|
||||
GameMain.Server.SendDirectChatMessage(moreAgentsMsgBox, traitorClient);
|
||||
|
||||
Client ownerClient = server.ConnectedClients.Find(c => c.Connection == server.OwnerConnection);
|
||||
if (traitorClient != ownerClient && ownerClient != null && ownerClient.Character == null)
|
||||
{
|
||||
var ownerMsg = ChatMessage.Create(
|
||||
null,//TextManager.Get("NewTraitor"),
|
||||
TextManager.GetWithVariables("TraitorStartMessageServer", new string[2] { "[targetname]", "[traitorname]" }, new string[2] { TargetCharacter.Name, Character.Name }),
|
||||
ChatMessageType.MessageBox,
|
||||
null
|
||||
);
|
||||
GameMain.Server.SendDirectChatMessage(ownerMsg, ownerClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial class TraitorManager
|
||||
{
|
||||
private static string wordsTxt = Path.Combine("Content", "CodeWords.txt");
|
||||
|
||||
public List<Traitor> TraitorList
|
||||
{
|
||||
get { return traitorList; }
|
||||
}
|
||||
|
||||
private List<Traitor> traitorList = new List<Traitor>();
|
||||
|
||||
public string codeWords, codeResponse;
|
||||
|
||||
public TraitorManager(GameServer server, int traitorCount)
|
||||
{
|
||||
if (traitorCount < 1) //what why how
|
||||
{
|
||||
traitorCount = 1;
|
||||
DebugConsole.ThrowError("Traitor Manager: TraitorCount somehow ended up less than 1, setting it to 1.");
|
||||
}
|
||||
Start(server, traitorCount);
|
||||
}
|
||||
|
||||
private void Start(GameServer server, int traitorCount)
|
||||
{
|
||||
if (server == null) return;
|
||||
|
||||
List<Character> characters = new List<Character>(); //ANYONE can be a target.
|
||||
List<Character> traitorCandidates = new List<Character>(); //Keep this to not re-pick traitors twice
|
||||
foreach (Client client in server.ConnectedClients)
|
||||
{
|
||||
if (client.Character != null)
|
||||
{
|
||||
characters.Add(client.Character);
|
||||
traitorCandidates.Add(client.Character);
|
||||
}
|
||||
}
|
||||
|
||||
if (server.Character != null)
|
||||
{
|
||||
characters.Add(server.Character); //Add host character
|
||||
traitorCandidates.Add(server.Character);
|
||||
}
|
||||
|
||||
if (characters.Count < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
codeWords = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
|
||||
codeResponse = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
|
||||
|
||||
while (traitorCount-- > 0)
|
||||
{
|
||||
if (traitorCandidates.Count <= 0) break;
|
||||
|
||||
int traitorIndex = Rand.Int(traitorCandidates.Count);
|
||||
Character traitorCharacter = traitorCandidates[traitorIndex];
|
||||
traitorCandidates.Remove(traitorCharacter);
|
||||
|
||||
//Add them to the list
|
||||
traitorList.Add(new Traitor(traitorCharacter));
|
||||
}
|
||||
|
||||
//Now that traitors have been decided, let's do objectives in post for deciding things like Document Exchange.
|
||||
foreach (Traitor traitor in traitorList)
|
||||
{
|
||||
Character traitorCharacter = traitor.Character;
|
||||
int targetIndex = Rand.Int(characters.Count);
|
||||
while (characters[targetIndex] == traitorCharacter) //Cannot target self
|
||||
{
|
||||
targetIndex = Rand.Int(characters.Count);
|
||||
}
|
||||
|
||||
Character targetCharacter = characters[targetIndex];
|
||||
traitor.TargetCharacter = targetCharacter;
|
||||
traitor.Greet(server, codeWords, codeResponse);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetEndMessage()
|
||||
{
|
||||
if (GameMain.Server == null || traitorList.Count <= 0) return "";
|
||||
|
||||
string endMessage = "";
|
||||
|
||||
foreach (Traitor traitor in traitorList)
|
||||
{
|
||||
Character traitorCharacter = traitor.Character;
|
||||
Character targetCharacter = traitor.TargetCharacter;
|
||||
string messageTag;
|
||||
|
||||
if (targetCharacter.IsDead) //Partial or complete mission success
|
||||
{
|
||||
if (traitorCharacter.IsDead)
|
||||
{
|
||||
messageTag = "TraitorEndMessageSuccessTraitorDead";
|
||||
}
|
||||
else if (traitorCharacter.LockHands)
|
||||
{
|
||||
messageTag = "TraitorEndMessageSuccessTraitorDetained";
|
||||
}
|
||||
else
|
||||
messageTag = "TraitorEndMessageSuccess";
|
||||
}
|
||||
else //Partial or complete failure
|
||||
{
|
||||
if (traitorCharacter.IsDead)
|
||||
{
|
||||
messageTag = "TraitorEndMessageFailureTraitorDead";
|
||||
}
|
||||
else if (traitorCharacter.LockHands)
|
||||
{
|
||||
messageTag = "TraitorEndMessageFailureTraitorDetained";
|
||||
}
|
||||
else
|
||||
{
|
||||
messageTag = "TraitorEndMessageFailure";
|
||||
}
|
||||
}
|
||||
|
||||
endMessage += (TextManager.ReplaceGenderPronouns(TextManager.GetWithVariables(messageTag, new string[2] { "[traitorname]", "[targetname]" },
|
||||
new string[2] { traitorCharacter.Name, targetCharacter.Name }), traitorCharacter.Info.Gender) + "\n");
|
||||
}
|
||||
|
||||
return endMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Controller : ItemComponent, IServerSerializable
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -11,7 +8,7 @@ namespace Barotrauma.Items.Components
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
//force can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(targetForce / 10.0f));
|
||||
msg.WriteRangedInteger((int)(targetForce / 10.0f), -10, 10);
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma.Items.Components
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
int itemIndex = fabricatedItem == null ? -1 : fabricationRecipes.IndexOf(fabricatedItem);
|
||||
msg.WriteRangedIntegerDeprecated(-1, fabricationRecipes.Count - 1, itemIndex);
|
||||
msg.WriteRangedInteger(itemIndex, -1, fabricationRecipes.Count - 1);
|
||||
UInt16 userID = fabricatedItem == null || user == null ? (UInt16)0 : user.ID;
|
||||
msg.Write(userID);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(flowPercentage / 10.0f));
|
||||
msg.WriteRangedInteger((int)(flowPercentage / 10.0f), -10, 10);
|
||||
msg.Write(IsActive);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
|
||||
msg.WriteRangedInteger((int)(rechargeSpeed / MaxRechargeSpeed * 10), 0, 10);
|
||||
|
||||
float chargeRatio = MathHelper.Clamp(charge / capacity, 0.0f, 1.0f);
|
||||
msg.WriteRangedSingle(chargeRatio, 0.0f, 1.0f, 8);
|
||||
|
||||
@@ -88,7 +88,10 @@ namespace Barotrauma.Items.Components
|
||||
existingWire.RemoveConnection(item);
|
||||
item.GetComponent<ConnectionPanel>()?.DisconnectedWires.Add(existingWire);
|
||||
|
||||
GameMain.Server.KarmaManager.OnWireDisconnected(c.Character, existingWire);
|
||||
if (!wires.Any(w => w.Contains(existingWire)))
|
||||
{
|
||||
GameMain.Server.KarmaManager.OnWireDisconnected(c.Character, existingWire);
|
||||
}
|
||||
|
||||
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
|
||||
{
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace Barotrauma.Items.Components
|
||||
int nodeStartIndex = eventIndex * MaxNodesPerNetworkEvent;
|
||||
int nodeCount = MathHelper.Clamp(nodes.Count - nodeStartIndex, 0, MaxNodesPerNetworkEvent);
|
||||
|
||||
msg.WriteRangedIntegerDeprecated(0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent), eventIndex);
|
||||
msg.WriteRangedIntegerDeprecated(0, MaxNodesPerNetworkEvent, nodeCount);
|
||||
msg.WriteRangedInteger(eventIndex, 0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent));
|
||||
msg.WriteRangedInteger(nodeCount, 0, MaxNodesPerNetworkEvent);
|
||||
for (int i = nodeStartIndex; i < nodeStartIndex + nodeCount; i++)
|
||||
{
|
||||
msg.Write(nodes[i].X);
|
||||
|
||||
@@ -11,13 +11,13 @@ namespace Barotrauma
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
{
|
||||
List<Item> prevItems = new List<Item>(Items);
|
||||
ushort[] newItemIDs = new ushort[capacity];
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
byte itemCount = msg.ReadByte();
|
||||
ushort[] newItemIDs = new ushort[itemCount];
|
||||
for (int i = 0; i < itemCount; i++)
|
||||
{
|
||||
newItemIDs[i] = msg.ReadUInt16();
|
||||
}
|
||||
|
||||
|
||||
if (c == null || c.Character == null) return;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Barotrauma
|
||||
{
|
||||
errorMsg = "Failed to write a network event for the item \"" + Name + "\" - event type not set.";
|
||||
}
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)NetEntityEvent.Type.Invalid);
|
||||
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
DebugConsole.Log(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:InvalidData" + Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma
|
||||
int initialWritePos = msg.LengthBits;
|
||||
|
||||
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
|
||||
msg.WriteRangedInteger((int)eventType, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
switch (eventType)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
@@ -54,7 +54,7 @@ namespace Barotrauma
|
||||
errorMsg = "Failed to write a component state event for the item \"" + Name + "\" - component \"" + components[componentIndex] + "\" is not server serializable.";
|
||||
break;
|
||||
}
|
||||
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, componentIndex);
|
||||
msg.WriteRangedInteger(componentIndex, 0, components.Count - 1);
|
||||
(components[componentIndex] as IServerSerializable).ServerWrite(msg, c, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
@@ -74,7 +74,7 @@ namespace Barotrauma
|
||||
errorMsg = "Failed to write an inventory state event for the item \"" + Name + "\" - component \"" + components[containerIndex] + "\" is not server serializable.";
|
||||
break;
|
||||
}
|
||||
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, containerIndex);
|
||||
msg.WriteRangedInteger(containerIndex, 0, components.Count - 1);
|
||||
(components[containerIndex] as ItemContainer).Inventory.ServerWrite(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
@@ -91,7 +91,7 @@ namespace Barotrauma
|
||||
byte targetLimbIndex = targetLimb != null && targetCharacter != null ? (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb) : (byte)255;
|
||||
|
||||
msg.Write((byte)components.IndexOf(targetComponent));
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(ActionType)).Length - 1, (int)actionType);
|
||||
msg.WriteRangedInteger((int)actionType, 0, Enum.GetValues(typeof(ActionType)).Length - 1);
|
||||
msg.Write(targetID);
|
||||
msg.Write(targetLimbIndex);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace Barotrauma
|
||||
Character targetCharacter = FindEntityByID(targetID) as Character;
|
||||
byte targetLimbIndex = targetLimb != null && targetCharacter != null ? (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb) : (byte)255;
|
||||
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(ActionType)).Length - 1, (int)actionType);
|
||||
msg.WriteRangedInteger((int)actionType, 0, Enum.GetValues(typeof(ActionType)).Length - 1);
|
||||
msg.Write((byte)(targetComponent == null ? 255 : components.IndexOf(targetComponent)));
|
||||
msg.Write(targetID);
|
||||
msg.Write(targetLimbIndex);
|
||||
@@ -132,7 +132,7 @@ namespace Barotrauma
|
||||
//something went wrong - rewind the write position and write invalid event type to prevent creating an unreadable event
|
||||
msg.BitPosition = initialWritePos;
|
||||
msg.LengthBits = initialWritePos;
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)NetEntityEvent.Type.Invalid);
|
||||
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
DebugConsole.Log(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:" + errorMsg, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
@@ -345,7 +345,7 @@ namespace Barotrauma
|
||||
|
||||
if (!ItemList.Contains(this))
|
||||
{
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.";
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Barotrauma
|
||||
message.Write(FireSources.Count > 0);
|
||||
if (FireSources.Count > 0)
|
||||
{
|
||||
message.WriteRangedIntegerDeprecated(0, 16, Math.Min(FireSources.Count, 16));
|
||||
message.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
|
||||
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
|
||||
{
|
||||
var fireSource = FireSources[i];
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma.Networking
|
||||
this.ExpirationTime = expirationTime;
|
||||
this.UniqueIdentifier = LastIdentifier; LastIdentifier++;
|
||||
|
||||
this.IsRangeBan = IP.IndexOf(".x")>-1;
|
||||
this.IsRangeBan = IP.IndexOf(".x") > -1;
|
||||
}
|
||||
|
||||
public BannedPlayer(string name, ulong steamID, string reason, DateTime? expirationTime)
|
||||
@@ -30,6 +30,8 @@ namespace Barotrauma.Networking
|
||||
this.UniqueIdentifier = LastIdentifier; LastIdentifier++;
|
||||
|
||||
this.IsRangeBan = false;
|
||||
|
||||
this.IP = "";
|
||||
}
|
||||
|
||||
public bool CompareTo(string ipCompare)
|
||||
@@ -276,28 +278,42 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
if (!c.HasPermission(ClientPermissions.Ban))
|
||||
try
|
||||
{
|
||||
outMsg.Write(false); outMsg.WritePadBits();
|
||||
return;
|
||||
}
|
||||
outMsg.Write(true);
|
||||
outMsg.Write(c.Connection == GameMain.Server.OwnerConnection);
|
||||
if (outMsg == null) { throw new ArgumentException("OutMsg was null"); }
|
||||
if (GameMain.Server == null) { throw new Exception("GameMain.Server was null"); }
|
||||
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteVariableUInt32((UInt32)bannedPlayers.Count);
|
||||
for (int i = 0; i < bannedPlayers.Count; i++)
|
||||
{
|
||||
BannedPlayer bannedPlayer = bannedPlayers[i];
|
||||
|
||||
outMsg.Write(bannedPlayer.Name);
|
||||
outMsg.Write(bannedPlayer.UniqueIdentifier);
|
||||
outMsg.Write(bannedPlayer.IsRangeBan); outMsg.WritePadBits();
|
||||
if (c.Connection == GameMain.Server.OwnerConnection)
|
||||
if (!c.HasPermission(ClientPermissions.Ban))
|
||||
{
|
||||
outMsg.Write(bannedPlayer.IP);
|
||||
outMsg.Write(bannedPlayer.SteamID);
|
||||
outMsg.Write(false); outMsg.WritePadBits();
|
||||
return;
|
||||
}
|
||||
|
||||
outMsg.Write(true);
|
||||
outMsg.Write(c.Connection == GameMain.Server.OwnerConnection);
|
||||
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteVariableUInt32((UInt32)bannedPlayers.Count);
|
||||
for (int i = 0; i < bannedPlayers.Count; i++)
|
||||
{
|
||||
BannedPlayer bannedPlayer = bannedPlayers[i];
|
||||
|
||||
outMsg.Write(bannedPlayer.Name);
|
||||
outMsg.Write(bannedPlayer.UniqueIdentifier);
|
||||
outMsg.Write(bannedPlayer.IsRangeBan); outMsg.WritePadBits();
|
||||
if (c.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
outMsg.Write(bannedPlayer.IP);
|
||||
outMsg.Write(bannedPlayer.SteamID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Error while writing banlist. {" + e + "}\n" + e.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("Banlist.ServerAdminWrite", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,11 @@ namespace Barotrauma
|
||||
partial class EntitySpawner : Entity, IServerSerializable
|
||||
{
|
||||
public void CreateNetworkEvent(Entity entity, bool remove)
|
||||
{
|
||||
CreateNetworkEventProjSpecific(entity, remove);
|
||||
}
|
||||
|
||||
partial void CreateNetworkEventProjSpecific(Entity entity, bool remove)
|
||||
{
|
||||
if (GameMain.Server != null && entity != null)
|
||||
{
|
||||
|
||||
@@ -264,17 +264,15 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
newClient.GivePermission(ClientPermissions.All);
|
||||
newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);
|
||||
|
||||
GameMain.Server.UpdateClientPermissions(newClient);
|
||||
GameMain.Server.SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
|
||||
SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
|
||||
}
|
||||
|
||||
GameMain.Server.SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);
|
||||
SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);
|
||||
serverSettings.ServerDetailsChanged = true;
|
||||
|
||||
if (previousPlayer != null && previousPlayer.Name != newClient.Name)
|
||||
{
|
||||
GameMain.Server.SendChatMessage($"ServerMessage.PreviousClientName~[client]={clName}~[previousname]={previousPlayer.Name}", ChatMessageType.Server, null);
|
||||
SendChatMessage($"ServerMessage.PreviousClientName~[client]={clName}~[previousname]={previousPlayer.Name}", ChatMessageType.Server, null);
|
||||
previousPlayer.Name = newClient.Name;
|
||||
}
|
||||
|
||||
@@ -299,6 +297,8 @@ namespace Barotrauma.Networking
|
||||
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
|
||||
}
|
||||
}
|
||||
|
||||
UpdateClientPermissions(newClient);
|
||||
}
|
||||
|
||||
private void OnClientDisconnect(NetworkConnection connection, string disconnectMsg)
|
||||
@@ -653,9 +653,18 @@ namespace Barotrauma.Networking
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to write a network message for the client \"" + c.Name + "\"!", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.Update:ClientWriteFailed" + e.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to write a network message for the client \"" + c.Name + "\"! (MidRoundSyncing: " + c.NeedsMidRoundSync + ")\n"
|
||||
+ e.Message + "\n" + e.StackTrace);
|
||||
|
||||
string errorMsg = "Failed to write a network message for the client \"" + c.Name + "\"! (MidRoundSyncing: " + c.NeedsMidRoundSync + ")\n"
|
||||
+ e.Message + "\n" + e.StackTrace;
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
|
||||
}
|
||||
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameServer.Update:ClientWriteFailed" + e.StackTrace,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,7 +841,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);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:" + errorStr, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
|
||||
|
||||
if (c.Connection == OwnerConnection)
|
||||
{
|
||||
@@ -1475,7 +1484,7 @@ namespace Barotrauma.Networking
|
||||
private void WriteClientList(Client c, IWriteMessage outmsg)
|
||||
{
|
||||
bool hasChanged = NetIdUtils.IdMoreRecent(LastClientListUpdateID, c.LastRecvClientListUpdate);
|
||||
if (!hasChanged) return;
|
||||
if (!hasChanged) { return; }
|
||||
|
||||
outmsg.Write((byte)ServerNetObject.CLIENT_LIST);
|
||||
outmsg.Write(LastClientListUpdateID);
|
||||
@@ -1502,6 +1511,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
outmsg.Write((byte)ServerNetObject.SYNC_IDS);
|
||||
|
||||
int settingsBytes = outmsg.LengthBytes;
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(GameMain.NetLobbyScreen.LastUpdateID, c.LastRecvLobbyUpdate))
|
||||
{
|
||||
outmsg.Write(true);
|
||||
@@ -1534,9 +1545,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
outmsg.Write(serverSettings.AllowSpectating);
|
||||
|
||||
outmsg.WriteRangedIntegerDeprecated(0, 2, (int)serverSettings.TraitorsEnabled);
|
||||
outmsg.WriteRangedInteger((int)serverSettings.TraitorsEnabled, 0, 2);
|
||||
|
||||
outmsg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(MissionType)).Length - 1, (GameMain.NetLobbyScreen.MissionTypeIndex));
|
||||
outmsg.WriteRangedInteger((GameMain.NetLobbyScreen.MissionTypeIndex), 0, Enum.GetValues(typeof(MissionType)).Length - 1);
|
||||
|
||||
outmsg.Write((byte)GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.LevelSeed);
|
||||
@@ -1556,9 +1567,12 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
settingsBytes = outmsg.LengthBytes - settingsBytes;
|
||||
|
||||
int campaignBytes = outmsg.LengthBytes;
|
||||
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
if (campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500 &&
|
||||
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
|
||||
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
|
||||
{
|
||||
outmsg.Write(true);
|
||||
@@ -1570,12 +1584,20 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
campaignBytes = outmsg.LengthBytes - campaignBytes;
|
||||
|
||||
outmsg.Write(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
|
||||
|
||||
WriteClientList(c, outmsg);
|
||||
int clientListBytes = outmsg.LengthBytes;
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500)
|
||||
{
|
||||
WriteClientList(c, outmsg);
|
||||
}
|
||||
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - outmsg.LengthBytes;
|
||||
|
||||
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
@@ -1597,7 +1619,14 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (outmsg.LengthBytes > MsgConstants.MTU)
|
||||
{
|
||||
DebugConsole.ThrowError("Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")");
|
||||
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")";
|
||||
errorMsg +=
|
||||
" Client list size: " + clientListBytes + " bytes\n" +
|
||||
" Chat message size: " + chatMessageBytes + " bytes\n" +
|
||||
" Campaign size: " + campaignBytes + " bytes\n" +
|
||||
" Settings size: " + settingsBytes + " bytes\n\n";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
|
||||
@@ -2018,6 +2047,8 @@ namespace Barotrauma.Networking
|
||||
c.PositionUpdateLastSent.Clear();
|
||||
}
|
||||
|
||||
KarmaManager.OnRoundEnded();
|
||||
|
||||
#if DEBUG
|
||||
messageCount.Clear();
|
||||
#endif
|
||||
@@ -2644,25 +2675,48 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
//send the message to the client whose permissions are being modified and the clients who are allowed to modify permissions
|
||||
List<Client> recipients = new List<Client>() { client };
|
||||
foreach (Client otherClient in connectedClients)
|
||||
{
|
||||
if (otherClient.HasPermission(ClientPermissions.ManagePermissions) && !recipients.Contains(otherClient))
|
||||
{
|
||||
recipients.Add(otherClient);
|
||||
}
|
||||
}
|
||||
foreach (Client recipient in recipients)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(SendClientPermissionsAfterClientListSynced(recipient, client));
|
||||
}
|
||||
serverSettings.SaveClientPermissions();
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<object> SendClientPermissionsAfterClientListSynced(Client recipient, Client client)
|
||||
{
|
||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
|
||||
while (recipient.LastRecvClientListUpdate < LastClientListUpdateID)
|
||||
{
|
||||
if (DateTime.Now > timeOut || GameMain.Server == null || !connectedClients.Contains(recipient))
|
||||
{
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SendClientPermissions(recipient, client);
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
|
||||
private void SendClientPermissions(Client recipient, Client client)
|
||||
{
|
||||
if (recipient?.Connection == null) { return; }
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.PERMISSIONS);
|
||||
client.WritePermissions(msg);
|
||||
|
||||
//send the message to the client whose permissions are being modified and the clients who are allowed to modify permissions
|
||||
List<NetworkConnection> recipients = new List<NetworkConnection>() { client.Connection };
|
||||
foreach (Client otherClient in connectedClients)
|
||||
{
|
||||
if (otherClient.HasPermission(ClientPermissions.ManagePermissions) && !recipients.Contains(otherClient.Connection))
|
||||
{
|
||||
recipients.Add(otherClient.Connection);
|
||||
}
|
||||
}
|
||||
foreach (NetworkConnection c in recipients)
|
||||
{
|
||||
serverPeer.Send(msg, c, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
serverSettings.SaveClientPermissions();
|
||||
serverPeer.Send(msg, recipient.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void GiveAchievement(Character character, string achievementIdentifier)
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace Barotrauma
|
||||
{
|
||||
public List<Pair<Wire, float>> WireDisconnectTime = new List<Pair<Wire, float>>();
|
||||
|
||||
//the client's karma value when they were last sent a notification about it (e.g. "your karma is very low")
|
||||
public float PreviousNotifiedKarma;
|
||||
|
||||
public float StructureDamageAccumulator;
|
||||
@@ -23,6 +22,13 @@ namespace Barotrauma
|
||||
get { return Math.Max(StructureDamageAccumulator, structureDamagePerSecond); }
|
||||
set { structureDamagePerSecond = value; }
|
||||
}
|
||||
|
||||
//when did a given character last attack this one
|
||||
public Dictionary<Character, double> LastAttackTime
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new Dictionary<Character, double>();
|
||||
}
|
||||
|
||||
public bool TestMode = false;
|
||||
@@ -31,9 +37,7 @@ namespace Barotrauma
|
||||
private readonly List<Client> bannedClients = new List<Client>();
|
||||
|
||||
private DateTime perSecondUpdate;
|
||||
|
||||
private double KarmaNotificationTime;
|
||||
|
||||
|
||||
public void UpdateClients(IEnumerable<Client> clients, float deltaTime)
|
||||
{
|
||||
if (!GameMain.Server.GameStarted) { return; }
|
||||
@@ -41,32 +45,34 @@ namespace Barotrauma
|
||||
bannedClients.Clear();
|
||||
foreach (Client client in clients)
|
||||
{
|
||||
var clientMemory = GetClientMemory(client);
|
||||
UpdateClient(client, deltaTime);
|
||||
|
||||
if (perSecondUpdate < DateTime.Now)
|
||||
{
|
||||
var clientMemory = GetClientMemory(client);
|
||||
clientMemory.StructureDamagePerSecond = clientMemory.StructureDamageAccumulator;
|
||||
clientMemory.StructureDamageAccumulator = 0.0f;
|
||||
|
||||
var toRemove = clientMemory.LastAttackTime.Where(pair => pair.Value < Timing.TotalTime - AllowedRetaliationTime).Select(pair => pair.Key).ToList();
|
||||
foreach (var lastAttacker in toRemove)
|
||||
{
|
||||
clientMemory.LastAttackTime.Remove(lastAttacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (perSecondUpdate < DateTime.Now)
|
||||
{
|
||||
perSecondUpdate = DateTime.Now + new TimeSpan(0, 0, 1);
|
||||
}
|
||||
|
||||
if (TestMode || Timing.TotalTime > KarmaNotificationTime)
|
||||
{
|
||||
foreach (Client client in clients)
|
||||
{
|
||||
SendKarmaNotifications(client);
|
||||
}
|
||||
KarmaNotificationTime = Timing.TotalTime + KarmaNotificationInterval;
|
||||
perSecondUpdate = DateTime.Now + new TimeSpan(0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
foreach (Client bannedClient in bannedClients)
|
||||
{
|
||||
if (bannedClient.KarmaKickCount < KicksBeforeBan)
|
||||
bannedClient.KarmaKickCount++;
|
||||
if (bannedClient.KarmaKickCount <= KicksBeforeBan)
|
||||
{
|
||||
GameMain.Server.KickClient(bannedClient, $"KarmaKicked~[banthreshold]={(int)KickBanThreshold}", resetKarma: true);
|
||||
}
|
||||
@@ -74,15 +80,17 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Server.BanClient(bannedClient, $"KarmaBanned~[banthreshold]={(int)KickBanThreshold}", duration: TimeSpan.FromSeconds(GameMain.Server.ServerSettings.AutoBanTime));
|
||||
}
|
||||
bannedClient.KarmaKickCount++;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendKarmaNotifications(Client client, string debugKarmaChangeReason = "")
|
||||
{
|
||||
//send a notification about karma changing if the karma has changed by x% within the last second
|
||||
|
||||
var clientMemory = GetClientMemory(client);
|
||||
float karmaChange = client.Karma - clientMemory.PreviousNotifiedKarma;
|
||||
if (Math.Abs(karmaChange) > KarmaNotificationInterval || (TestMode && Math.Abs(karmaChange) > 2.0f))
|
||||
if (Math.Abs(karmaChange) > 1.0f &&
|
||||
(TestMode || Math.Abs(karmaChange) / clientMemory.PreviousNotifiedKarma > KarmaNotificationInterval / 100.0f))
|
||||
{
|
||||
if (TestMode)
|
||||
{
|
||||
@@ -102,8 +110,8 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.Get(karmaChange < 0 ? "KarmaDecreasedUnknownAmount" : "KarmaIncreasedUnknownAmount"), client);
|
||||
}
|
||||
clientMemory.PreviousNotifiedKarma = client.Karma;
|
||||
}
|
||||
clientMemory.PreviousNotifiedKarma = client.Karma;
|
||||
}
|
||||
|
||||
private void UpdateClient(Client client, float deltaTime)
|
||||
@@ -156,7 +164,7 @@ namespace Barotrauma
|
||||
AdjustKarma(client.Character, karmaDecrease, "Disconnected excessive number of wires");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (client.Character?.Info?.Job.Prefab.Identifier == "captain" && client.Character.SelectedConstruction != null)
|
||||
{
|
||||
if (client.Character.SelectedConstruction.GetComponent<Steering>() != null)
|
||||
@@ -180,6 +188,18 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRoundEnded()
|
||||
{
|
||||
if (ResetKarmaBetweenRounds)
|
||||
{
|
||||
clientMemories.Clear();
|
||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
client.Karma = Math.Max(50.0f, client.Karma);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClientDisconnected(Client client)
|
||||
{
|
||||
clientMemories.Remove(client);
|
||||
@@ -210,7 +230,41 @@ namespace Barotrauma
|
||||
isEnemy = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool targetIsHusk = target.CharacterHealth?.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active;
|
||||
bool attackerIsHusk = attacker.CharacterHealth?.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active;
|
||||
//huskified characters count as enemies to healthy characters and vice versa
|
||||
if (targetIsHusk != attackerIsHusk) { isEnemy = true; }
|
||||
|
||||
if (appliedAfflictions != null)
|
||||
{
|
||||
foreach (Affliction affliction in appliedAfflictions)
|
||||
{
|
||||
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
|
||||
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
|
||||
}
|
||||
}
|
||||
|
||||
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == target);
|
||||
if (damage > 0 && targetClient != null)
|
||||
{
|
||||
var targetMemory = GetClientMemory(targetClient);
|
||||
targetMemory.LastAttackTime[attacker] = Timing.TotalTime;
|
||||
}
|
||||
|
||||
Client attackerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == attacker);
|
||||
if (attackerClient != null)
|
||||
{
|
||||
//if the attacker has been attacked by the target within the last x seconds, ignore the damage
|
||||
//(= no karma penalty from retaliating against someone who attacked you)
|
||||
var attackerMemory = GetClientMemory(attackerClient);
|
||||
if (attackerMemory.LastAttackTime.ContainsKey(target) &&
|
||||
attackerMemory.LastAttackTime[target] > Timing.TotalTime - AllowedRetaliationTime)
|
||||
{
|
||||
damage = Math.Min(damage, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//attacking/healing clowns has a smaller effect on karma
|
||||
if (target.HasEquippedItem("clownmask") &&
|
||||
target.HasEquippedItem("clowncostume"))
|
||||
@@ -218,15 +272,21 @@ namespace Barotrauma
|
||||
damage *= 0.5f;
|
||||
}
|
||||
|
||||
if (appliedAfflictions != null)
|
||||
//smaller karma penalty for attacking someone who's aiming with a weapon
|
||||
if (damage > 0.0f &&
|
||||
target.IsKeyDown(InputType.Aim) &&
|
||||
target.SelectedItems.Any(it => it != null && (it.GetComponent<MeleeWeapon>() != null || it.GetComponent<RangedWeapon>() != null)))
|
||||
{
|
||||
foreach (Affliction affliction in appliedAfflictions)
|
||||
{
|
||||
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
|
||||
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
|
||||
}
|
||||
damage *= 0.5f;
|
||||
}
|
||||
|
||||
//damage scales according to the karma of the target
|
||||
//(= smaller karma penalty from attacking someone who has a low karma)
|
||||
if (damage > 0 && targetClient != null)
|
||||
{
|
||||
damage *= MathUtils.InverseLerp(0.0f, 50.0f, targetClient.Karma);
|
||||
}
|
||||
|
||||
if (isEnemy)
|
||||
{
|
||||
if (damage > 0)
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace Barotrauma.Networking
|
||||
Retries = 0;
|
||||
SteamID = null;
|
||||
PasswordSalt = null;
|
||||
UpdateTime = Timing.TotalTime;
|
||||
TimeOut = 20.0;
|
||||
UpdateTime = Timing.TotalTime+Timing.Step*3.0;
|
||||
TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
AuthSessionStarted = false;
|
||||
}
|
||||
}
|
||||
@@ -319,7 +319,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
pendingClient.TimeOut = 20.0;
|
||||
pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
@@ -327,6 +327,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (pendingClient.InitializationStep != initializationStep) return;
|
||||
|
||||
pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;
|
||||
|
||||
switch (initializationStep)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
@@ -522,6 +524,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
OnInitializationComplete?.Invoke(newConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -554,6 +557,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
NetSendResult result = netServer.SendMessage(outMsg, pendingClient.Connection, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send initialization step " + pendingClient.InitializationStep.ToString() + " to pending client: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
//DebugConsole.NewMessage("sent update to pending client: "+result);
|
||||
}
|
||||
|
||||
@@ -588,7 +595,7 @@ namespace Barotrauma.Networking
|
||||
if (netServer == null) { return; }
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.SteamID == steamID);
|
||||
DebugConsole.NewMessage(steamID + " validation: " + status+", "+(pendingClient!=null));
|
||||
DebugConsole.Log(steamID + " validation: " + status+", "+(pendingClient!=null));
|
||||
|
||||
if (pendingClient == null)
|
||||
{
|
||||
@@ -653,7 +660,11 @@ namespace Barotrauma.Networking
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
|
||||
NetSendResult result = netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to "+conn.Name+": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Disconnect(NetworkConnection conn,string msg=null)
|
||||
|
||||
@@ -40,14 +40,14 @@ namespace Barotrauma.Networking
|
||||
Retries = 0;
|
||||
SteamID = steamId;
|
||||
PasswordSalt = null;
|
||||
UpdateTime = Timing.TotalTime;
|
||||
TimeOut = 20.0;
|
||||
UpdateTime = Timing.TotalTime+Timing.Step*3.0;
|
||||
TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
AuthSessionStarted = false;
|
||||
}
|
||||
|
||||
public void Heartbeat()
|
||||
{
|
||||
TimeOut = 5.0;
|
||||
TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("got server message from" + senderSteamId.ToString());
|
||||
DebugConsole.ThrowError("Got server message from" + senderSteamId.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -346,7 +346,11 @@ namespace Barotrauma.Networking
|
||||
NetOutgoingMessage outMsg = netServer.CreateMessage();
|
||||
outMsg.Write(OwnerSteamID);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
|
||||
netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send connection confirmation message to owner: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
break;
|
||||
case NetConnectionStatus.Disconnected:
|
||||
DebugConsole.NewMessage("Owner disconnected: closing the server...");
|
||||
@@ -360,7 +364,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
pendingClient.TimeOut = 20.0;
|
||||
pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
@@ -368,6 +372,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (pendingClient.InitializationStep != initializationStep) return;
|
||||
|
||||
pendingClient.UpdateTime = Timing.TotalTime+Timing.Step;
|
||||
|
||||
switch (initializationStep)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
@@ -549,6 +555,10 @@ namespace Barotrauma.Networking
|
||||
if (netConnection != null)
|
||||
{
|
||||
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send initialization step " + pendingClient.InitializationStep.ToString() + " to pending client: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +619,11 @@ namespace Barotrauma.Networking
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netServer.SendMessage(lidgrenMsg, netConnection, lidgrenDeliveryMethod);
|
||||
NetSendResult result = netServer.SendMessage(lidgrenMsg, netConnection, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to " + conn.Name + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendDisconnectMessage(UInt64 steamId, string msg)
|
||||
@@ -622,7 +636,11 @@ namespace Barotrauma.Networking
|
||||
lidgrenMsg.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
|
||||
lidgrenMsg.Write(msg);
|
||||
|
||||
netServer.SendMessage(lidgrenMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
NetSendResult result = netServer.SendMessage(lidgrenMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send disconnect message to " + Steam.SteamManager.SteamIDUInt64ToString(steamId) + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
|
||||
private void Disconnect(NetworkConnection conn, string msg, bool sendDisconnectMessage)
|
||||
|
||||
@@ -327,7 +327,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetNames(typeof(State)).Length, (int)CurrentState);
|
||||
msg.WriteRangedInteger((int)CurrentState, 0, Enum.GetNames(typeof(State)).Length);
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write(HasPassword);
|
||||
outMsg.Write(isPublic);
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteRangedIntegerDeprecated(1, 60, TickRate);
|
||||
outMsg.WriteRangedInteger(TickRate, 1, 60);
|
||||
|
||||
WriteExtraCargo(outMsg);
|
||||
|
||||
@@ -236,8 +236,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
|
||||
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars",
|
||||
|
||||
string[] defaultAllowedClientNameChars =
|
||||
new string[] {
|
||||
"32-33",
|
||||
"38-46",
|
||||
@@ -248,8 +248,16 @@ namespace Barotrauma.Networking
|
||||
"95-122",
|
||||
"192-255",
|
||||
"384-591",
|
||||
"1024-1279"
|
||||
});
|
||||
"1024-1279",
|
||||
"19968-40959","13312-19903","131072-173791","173824-178207","178208-183983","63744-64255","194560-195103" //CJK
|
||||
};
|
||||
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", defaultAllowedClientNameChars);
|
||||
if (doc.Root.GetAttributeString("AllowedClientNameChars", "") == "65-90,97-122,48-59")
|
||||
{
|
||||
allowedClientNameCharsStr = defaultAllowedClientNameChars;
|
||||
}
|
||||
|
||||
foreach (string allowedClientNameCharRange in allowedClientNameCharsStr)
|
||||
{
|
||||
string[] splitRange = allowedClientNameCharRange.Split('-');
|
||||
@@ -275,7 +283,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (min > -1 && max > -1) AllowedClientNameChars.Add(new Pair<int, int>(min, max));
|
||||
if (min > -1 && max > -1) { AllowedClientNameChars.Add(new Pair<int, int>(min, max)); }
|
||||
}
|
||||
|
||||
AllowedRandomMissionTypes = new List<MissionType>();
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Barotrauma
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine == null || hull.Submarine.IsOutpost || hull.Submarine.TeamID != Traitor.Character.TeamID) { continue; }
|
||||
if (hull.Submarine == GameMain.Server?.RespawnManager?.RespawnShuttle) { continue; }
|
||||
++validHullsCount;
|
||||
floodingAmount += hull.WaterVolume / hull.Volume;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<Text file="Content/Texts/SimplifiedChineseVanilla.xml" />
|
||||
<Text file="Content/Texts/TraditionalChineseVanilla.xml" />
|
||||
<Text file="Content/Texts/CastilianSpanishVanilla.xml" />
|
||||
<Text file="Content/Texts/JapaneseVanilla.xml" />
|
||||
<Text file="Content/Texts/LatinamericanSpanishVanilla.xml" />
|
||||
<Text file="Content/Texts/PolishVanilla.xml" />
|
||||
<Text file="Content/Texts/TurkishVanilla.xml" />
|
||||
@@ -117,6 +118,11 @@
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_BrazilianPortuguese.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_SimplifiedChinese.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_TraditionalChinese.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_CastilianSpanish.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_Japanese.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_LatinamericanSpanish.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_Polish.xml"/>
|
||||
<NPCConversations file="Content/NPCConversations/NpcConversations_Turkish.xml"/>
|
||||
<Jobs file="Content/Jobs.xml" />
|
||||
<Sounds file="Content/Sounds/sounds.xml" />
|
||||
<Tutorials file="Content/Tutorials/Tutorials.xml" />
|
||||
|
||||
@@ -7,20 +7,22 @@
|
||||
karmaincrease="0.1"
|
||||
karmaincreasethreshold="50"
|
||||
structurerepairkarmaincrease="0.05"
|
||||
structuredamagekarmadecrease="0.1"
|
||||
structuredamagekarmadecrease="0.08"
|
||||
itemrepairkarmaincrease="0.03"
|
||||
reactoroverheatkarmadecrease="0.5"
|
||||
reactormeltdownkarmadecrease="30"
|
||||
damageenemykarmaincrease="0.1"
|
||||
damagefriendlykarmadecrease="0.2"
|
||||
damagefriendlykarmadecrease="0.15"
|
||||
extinguishfirekarmaincrease="1"
|
||||
allowedwiredisconnectionsperminute="3"
|
||||
allowedwiredisconnectionsperminute="5"
|
||||
wiredisconnectionkarmadecrease="6.0"
|
||||
steersubkarmaincrease="0.15"
|
||||
spamfilterkarmadecrease="15"
|
||||
herpesthreshold="40"
|
||||
kickbanthreshold="1"
|
||||
karmanotificationinterval="10" />
|
||||
kicksbeforeban="3"
|
||||
karmanotificationinterval="15"
|
||||
resetkarmabetweenrounds="true" />
|
||||
<Preset
|
||||
name="Strict"
|
||||
karmadecay="0.08"
|
||||
@@ -35,13 +37,15 @@
|
||||
damageenemykarmaincrease="0.1"
|
||||
damagefriendlykarmadecrease="0.3"
|
||||
extinguishfirekarmaincrease="1"
|
||||
allowedwiredisconnectionsperminute="1"
|
||||
allowedwiredisconnectionsperminute="3"
|
||||
wiredisconnectionkarmadecrease="10.0"
|
||||
steersubkarmaincrease="0.15"
|
||||
spamfilterkarmadecrease="25"
|
||||
herpesthreshold="40"
|
||||
kickbanthreshold="1"
|
||||
karmanotificationinterval="10" />
|
||||
kicksbeforeban="1"
|
||||
karmanotificationinterval="15"
|
||||
resetkarmabetweenrounds="true" />
|
||||
<Preset
|
||||
name="Custom"
|
||||
karmadecay="0.08"
|
||||
@@ -49,18 +53,20 @@
|
||||
karmaincrease="0.1"
|
||||
karmaincreasethreshold="50"
|
||||
structurerepairkarmaincrease="0.05"
|
||||
structuredamagekarmadecrease="0.1"
|
||||
structuredamagekarmadecrease="0.08"
|
||||
itemrepairkarmaincrease="0.03"
|
||||
reactoroverheatkarmadecrease="0.5"
|
||||
reactormeltdownkarmadecrease="30"
|
||||
damageenemykarmaincrease="0.1"
|
||||
damagefriendlykarmadecrease="0.2"
|
||||
damagefriendlykarmadecrease="0.15"
|
||||
extinguishfirekarmaincrease="1"
|
||||
allowedwiredisconnectionsperminute="3"
|
||||
allowedwiredisconnectionsperminute="5"
|
||||
wiredisconnectionkarmadecrease="6.0"
|
||||
steersubkarmaincrease="0.15"
|
||||
spamfilterkarmadecrease="15"
|
||||
herpesthreshold="40"
|
||||
kickbanthreshold="1"
|
||||
karmanotificationinterval="10" />
|
||||
kicksbeforeban="3"
|
||||
karmanotificationinterval="15"
|
||||
resetkarmabetweenrounds="true" />
|
||||
</KarmaManager>
|
||||
@@ -592,6 +592,9 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_BrazilianPortuguese.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_CastilianSpanish.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_English.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -602,6 +605,15 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_German.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Japanese.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_LatinamericanSpanish.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Polish.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Russian.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -611,6 +623,9 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_TraditionalChinese.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Turkish.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Splash_Daedalic.mp4">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -635,6 +650,9 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\GermanVanilla.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\JapaneseVanilla.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\LatinamericanSpanishVanilla.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -2399,6 +2417,12 @@
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Impact\SoftImpact3.ogg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\RepairLoop.ogg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\RewiringLoop.ogg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Tutorials\Dugong_Tutorial.sub">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -2420,6 +2444,9 @@
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\TraitorMissions.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Submarines\Nautilus.sub">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\CARRIER_alarmLoop.ogg">
|
||||
@@ -3593,4 +3620,4 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -387,14 +387,17 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateIdle(float deltaTime)
|
||||
{
|
||||
if (Character.Submarine == null && SimPosition.Y < ConvertUnits.ToSimUnits(Character.CharacterHealth.CrushDepth * 0.75f))
|
||||
if (Character.Submarine == null &&
|
||||
SimPosition.Y < ConvertUnits.ToSimUnits(Character.CharacterHealth.CrushDepth * 0.75f))
|
||||
{
|
||||
//steer straight up if very deep
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.UnitY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wallTarget != null) return;
|
||||
SteerInsideLevel(deltaTime);
|
||||
|
||||
if (wallTarget != null) { return; }
|
||||
|
||||
if (SelectedAiTarget != null)
|
||||
{
|
||||
@@ -451,6 +454,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SteerInsideLevel(deltaTime);
|
||||
}
|
||||
if (escapePoint != Vector2.Zero && Vector2.DistanceSquared(Character.SimPosition, escapePoint) > 1)
|
||||
{
|
||||
SteeringManager.SteeringSeek(escapePoint);
|
||||
@@ -1396,6 +1403,30 @@ namespace Barotrauma
|
||||
AttackingLimb = null;
|
||||
}
|
||||
|
||||
private void SteerInsideLevel(float deltaTime)
|
||||
{
|
||||
if (Level.Loaded == null) { return; }
|
||||
|
||||
Vector2 levelSimSize = new Vector2(
|
||||
ConvertUnits.ToSimUnits(Level.Loaded.Size.X),
|
||||
ConvertUnits.ToSimUnits(Level.Loaded.Size.Y));
|
||||
|
||||
float margin = 10.0f;
|
||||
|
||||
if (SimPosition.Y < 0.0f)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.UnitY * MathUtils.InverseLerp(0.0f, -margin, SimPosition.Y));
|
||||
}
|
||||
if (SimPosition.X < 0.0f)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.UnitX * MathUtils.InverseLerp(0.0f, -margin, SimPosition.X));
|
||||
}
|
||||
if (SimPosition.X > levelSimSize.X)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.UnitX * MathUtils.InverseLerp(levelSimSize.X, levelSimSize.X + margin, SimPosition.X));
|
||||
}
|
||||
}
|
||||
|
||||
private int GetMinimumPassableHoleCount()
|
||||
{
|
||||
return (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderSize) / Structure.WallSectionSize);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Barotrauma
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (DisableCrewAI || Character.IsUnconscious) return;
|
||||
if (DisableCrewAI || Character.IsUnconscious || Character.Removed) { return; }
|
||||
|
||||
float maxDistanceToSub = 3000;
|
||||
if (Character.Submarine != null || SelectedAiTarget?.Entity?.Submarine != null &&
|
||||
|
||||
@@ -312,8 +312,10 @@ namespace Barotrauma
|
||||
Vector2 colliderBottom = character.AnimController.GetColliderBottom();
|
||||
Vector2 colliderSize = collider.GetSize();
|
||||
Vector2 velocity = collider.LinearVelocity;
|
||||
// If the character is smaller than this, it fails to use the waypoint nodes, because they are always too high.
|
||||
float minHeight = 1;
|
||||
// Cannot use the head position, because not all characters have head or it can be below the total height of the character
|
||||
float characterHeight = colliderSize.Y + character.AnimController.ColliderHeightFromFloor;
|
||||
float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight);
|
||||
float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
|
||||
bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
|
||||
bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
|
||||
|
||||
@@ -132,7 +132,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (Frozen) return;
|
||||
if (MainLimb == null) { return; }
|
||||
|
||||
|
||||
levitatingCollider = true;
|
||||
|
||||
if (!character.AllowInput)
|
||||
{
|
||||
levitatingCollider = false;
|
||||
@@ -542,8 +544,6 @@ namespace Barotrauma
|
||||
//limbs are disabled when simple physics is enabled, no need to move them
|
||||
if (SimplePhysicsEnabled) { return; }
|
||||
|
||||
float mainLimbHeight = ColliderHeightFromFloor;
|
||||
|
||||
Vector2 colliderBottom = GetColliderBottom();
|
||||
|
||||
float movementAngle = 0.0f;
|
||||
@@ -569,9 +569,9 @@ namespace Barotrauma
|
||||
Vector2 pos = colliderBottom + Vector2.UnitY * TorsoPosition.Value;
|
||||
|
||||
if (torso != MainLimb)
|
||||
{
|
||||
pos.X = torso.SimPosition.X;
|
||||
else
|
||||
mainLimbHeight = TorsoPosition.Value;
|
||||
}
|
||||
|
||||
torso.MoveToPos(pos, TorsoMoveForce);
|
||||
torso.PullJointEnabled = true;
|
||||
@@ -591,9 +591,9 @@ namespace Barotrauma
|
||||
Vector2 pos = colliderBottom + Vector2.UnitY * HeadPosition.Value;
|
||||
|
||||
if (head != MainLimb)
|
||||
{
|
||||
pos.X = head.SimPosition.X;
|
||||
else
|
||||
mainLimbHeight = HeadPosition.Value;
|
||||
}
|
||||
|
||||
head.MoveToPos(pos, HeadMoveForce);
|
||||
head.PullJointEnabled = true;
|
||||
|
||||
@@ -1298,7 +1298,8 @@ namespace Barotrauma
|
||||
|
||||
Vector2 colliderPos = GetColliderBottom();
|
||||
|
||||
bool wasCritical = target.Vitality < 0.0f;
|
||||
float prevVitality = target.Vitality;
|
||||
bool wasCritical = prevVitality < 0.0f;
|
||||
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
|
||||
{
|
||||
@@ -1357,7 +1358,7 @@ namespace Barotrauma
|
||||
AfflictionPrefab.InternalDamage.Instantiate((CPRSettings.DamageSkillThreshold - skill) * CPRSettings.DamageSkillMultiplier,
|
||||
source: character)
|
||||
},
|
||||
0.0f, true, 0.0f, character);
|
||||
0.0f, true, 0.0f, attacker: null);
|
||||
}
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
|
||||
{
|
||||
@@ -1389,9 +1390,12 @@ namespace Barotrauma
|
||||
character.Info.IncreaseSkillLevel("medical", 0.5f, character.WorldPosition + Vector2.UnitY * 150.0f);
|
||||
SteamAchievementManager.OnCharacterRevived(target, character);
|
||||
lastReviveTime = (float)Timing.TotalTime;
|
||||
#if SERVER
|
||||
GameMain.Server?.KarmaManager?.OnCharacterHealthChanged(target, character, damage: Math.Min(prevVitality - target.Vitality, 0.0f));
|
||||
#endif
|
||||
//reset attacker, we don't want the character to start attacking us
|
||||
//because we caused a bit of damage to them during CPR
|
||||
if (target.LastAttacker == character) target.LastAttacker = null;
|
||||
if (target.LastAttacker == character) { target.LastAttacker = null; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class HumanoidAnimParams : ISerializableEntity
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public HumanoidAnimParams(string file)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
|
||||
Name = doc.Root.Name.ToString();
|
||||
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, doc.Root);
|
||||
}
|
||||
|
||||
[Serialize(0.3f, true), Editable]
|
||||
public float GetUpSpeed
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(1.54f, true), Editable]
|
||||
public float HeadPosition
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(1.15f, true), Editable]
|
||||
public float TorsoPosition
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
[Serialize(0.25f, true), Editable]
|
||||
public float HeadLeanAmount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.25f, true), Editable]
|
||||
public float TorsoLeanAmount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(5.0f, true), Editable]
|
||||
public float CycleSpeed
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(15.0f, true), Editable]
|
||||
public float FootMoveStrength
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Serialize(20.0f, true), Editable]
|
||||
public float FootRotateStrength
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
[Serialize("0.4,0.12", true), Editable]
|
||||
public Vector2 StepSize
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("0.0, 0.0", true), Editable]
|
||||
public Vector2 FootMoveOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(10.0f, true), Editable]
|
||||
public float LegCorrectionTorque
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(15.0f, true), Editable]
|
||||
public float ThighCorrectionTorque
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("0.4, 0.15", true), Editable]
|
||||
public Vector2 HandMoveAmount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("-0.15, 0.0", true), Editable]
|
||||
public Vector2 HandMoveOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.7f, true), Editable]
|
||||
public float HandMoveStrength
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(-1.0f, true), Editable]
|
||||
public float HandClampY
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1252,7 +1252,7 @@ namespace Barotrauma
|
||||
rayEnd.Y -= Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor*1.2f;
|
||||
|
||||
Vector2 colliderBottomDisplay = ConvertUnits.ToDisplayUnits(GetColliderBottom());
|
||||
if (!inWater && !character.IsDead && character.Stun <= 0f && levitatingCollider && Collider.LinearVelocity.Y>-ImpactTolerance)
|
||||
if (!inWater && !character.IsDead && character.Stun <= 0f && levitatingCollider && Collider.LinearVelocity.Y > -ImpactTolerance)
|
||||
{
|
||||
float closestFraction = 1.0f;
|
||||
Fixture closestFixture = null;
|
||||
|
||||
@@ -1484,6 +1484,9 @@ namespace Barotrauma
|
||||
return (wall == null || !wall.CastShadow) && (door == null || door.IsOpen);
|
||||
}
|
||||
|
||||
public bool HasItem(Item item, bool requireEquipped = false) =>
|
||||
requireEquipped ? HasEquippedItem(item) : item.FindParentInventory(i => i.Owner == this) != null;
|
||||
|
||||
public bool HasEquippedItem(Item item)
|
||||
{
|
||||
for (int i = 0; i < Inventory.Capacity; i++)
|
||||
@@ -1595,7 +1598,7 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
if (Screen.Selected == GameMain.SubEditorScreen) { hidden = false; }
|
||||
#endif
|
||||
if (!CanInteract || hidden) return false;
|
||||
if (!CanInteract || hidden || item.NonInteractable) return false;
|
||||
|
||||
if (item.ParentInventory != null)
|
||||
{
|
||||
|
||||
@@ -764,13 +764,13 @@ namespace Barotrauma
|
||||
|
||||
public void SetSkillLevel(string skillIdentifier, float level, Vector2 worldPos)
|
||||
{
|
||||
if (Job == null) return;
|
||||
if (Job == null) { return; }
|
||||
|
||||
var skill = Job.Skills.Find(s => s.Identifier == skillIdentifier);
|
||||
if (skill == null)
|
||||
{
|
||||
Job.Skills.Add(new Skill(skillIdentifier, level));
|
||||
OnSkillChanged(skillIdentifier, 0.0f, skill.Level, worldPos);
|
||||
OnSkillChanged(skillIdentifier, 0.0f, level, worldPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class Affliction
|
||||
{
|
||||
public readonly AfflictionPrefab Prefab;
|
||||
|
||||
public float Strength;
|
||||
|
||||
public float DamagePerSecond;
|
||||
public float DamagePerSecondTimer;
|
||||
public float PreviousVitalityDecrease;
|
||||
|
||||
/// <summary>
|
||||
/// Which character gave this affliction
|
||||
/// </summary>
|
||||
public Character Source;
|
||||
|
||||
public Affliction(AfflictionPrefab prefab, float strength)
|
||||
{
|
||||
Prefab = prefab;
|
||||
Strength = strength;
|
||||
}
|
||||
|
||||
public Affliction CreateMultiplied(float multiplier)
|
||||
{
|
||||
return Prefab.Instantiate(Strength * multiplier, Source);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Affliction (" + Prefab.Name + ")";
|
||||
}
|
||||
|
||||
public float GetVitalityDecrease(CharacterHealth characterHealth)
|
||||
{
|
||||
if (Strength < Prefab.ActivationThreshold) return 0.0f;
|
||||
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
|
||||
if (currentEffect == null) return 0.0f;
|
||||
if (currentEffect.MaxStrength - currentEffect.MinStrength <= 0.0f) return 0.0f;
|
||||
|
||||
float currVitalityDecrease = MathHelper.Lerp(
|
||||
currentEffect.MinVitalityDecrease,
|
||||
currentEffect.MaxVitalityDecrease,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
|
||||
if (currentEffect.MultiplyByMaxVitality) currVitalityDecrease *= characterHealth == null ? 100.0f : characterHealth.MaxVitality;
|
||||
|
||||
return currVitalityDecrease;
|
||||
}
|
||||
|
||||
public float GetScreenDistortStrength()
|
||||
{
|
||||
if (Strength < Prefab.ActivationThreshold) return 0.0f;
|
||||
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
|
||||
if (currentEffect == null) return 0.0f;
|
||||
if (currentEffect.MaxScreenDistortStrength - currentEffect.MinScreenDistortStrength <= 0.0f) return 0.0f;
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinScreenDistortStrength,
|
||||
currentEffect.MaxScreenDistortStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
}
|
||||
|
||||
public float GetRadialDistortStrength()
|
||||
{
|
||||
if (Strength < Prefab.ActivationThreshold) return 0.0f;
|
||||
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
|
||||
if (currentEffect == null) return 0.0f;
|
||||
if (currentEffect.MaxRadialDistortStrength - currentEffect.MinRadialDistortStrength <= 0.0f) return 0.0f;
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinRadialDistortStrength,
|
||||
currentEffect.MaxRadialDistortStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
}
|
||||
|
||||
public float GetChromaticAberrationStrength()
|
||||
{
|
||||
if (Strength < Prefab.ActivationThreshold) return 0.0f;
|
||||
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
|
||||
if (currentEffect == null) return 0.0f;
|
||||
if (currentEffect.MaxChromaticAberrationStrength - currentEffect.MinChromaticAberrationStrength <= 0.0f) return 0.0f;
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinChromaticAberrationStrength,
|
||||
currentEffect.MaxChromaticAberrationStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
}
|
||||
|
||||
public float GetScreenBlurStrength()
|
||||
{
|
||||
if (Strength < Prefab.ActivationThreshold) return 0.0f;
|
||||
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
|
||||
if (currentEffect == null) return 0.0f;
|
||||
if (currentEffect.MaxScreenBlurStrength - currentEffect.MinScreenBlurStrength <= 0.0f) return 0.0f;
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinScreenBlurStrength,
|
||||
currentEffect.MaxScreenBlurStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
}
|
||||
|
||||
public void CalculateDamagePerSecond(float currentVitalityDecrease)
|
||||
{
|
||||
DamagePerSecond = Math.Max(DamagePerSecond, currentVitalityDecrease - PreviousVitalityDecrease);
|
||||
if (DamagePerSecondTimer >= 1.0f)
|
||||
{
|
||||
DamagePerSecond = currentVitalityDecrease - PreviousVitalityDecrease;
|
||||
PreviousVitalityDecrease = currentVitalityDecrease;
|
||||
DamagePerSecondTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
|
||||
{
|
||||
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
|
||||
if (currentEffect == null) return;
|
||||
|
||||
Strength += currentEffect.StrengthChange * deltaTime;
|
||||
foreach (StatusEffect statusEffect in currentEffect.StatusEffects)
|
||||
{
|
||||
if (statusEffect.HasTargetType(StatusEffect.TargetType.Character))
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, characterHealth.Character);
|
||||
}
|
||||
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.Limb))
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, targetLimb);
|
||||
}
|
||||
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnActive, deltaTime, targetLimb.character, targetLimb.character.AnimController.Limbs.Cast<ISerializableEntity>().ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class AfflictionBleeding : Affliction
|
||||
{
|
||||
public AfflictionBleeding(AfflictionPrefab prefab, float strength) :
|
||||
base(prefab, strength)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
|
||||
{
|
||||
base.Update(characterHealth, targetLimb, deltaTime);
|
||||
characterHealth.BloodlossAmount += Strength * (1.0f / 60.0f) * deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,336 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static class CPRSettings
|
||||
{
|
||||
public static float ReviveChancePerSkill { get; private set; }
|
||||
public static float ReviveChanceExponent { get; private set; }
|
||||
public static float ReviveChanceMin { get; private set; }
|
||||
public static float ReviveChanceMax { get; private set; }
|
||||
public static float StabilizationPerSkill { get; private set; }
|
||||
public static float StabilizationMin { get; private set; }
|
||||
public static float StabilizationMax { get; private set; }
|
||||
public static float DamageSkillThreshold { get; private set; }
|
||||
public static float DamageSkillMultiplier { get; private set; }
|
||||
|
||||
public static void Load(XElement element)
|
||||
{
|
||||
ReviveChancePerSkill = Math.Max(element.GetAttributeFloat("revivechanceperskill", 0.01f), 0.0f);
|
||||
ReviveChanceExponent = Math.Max(element.GetAttributeFloat("revivechanceexponent", 2.0f), 0.0f);
|
||||
ReviveChanceMin = MathHelper.Clamp(element.GetAttributeFloat("revivechancemin", 0.05f), 0.0f, 1.0f);
|
||||
ReviveChanceMax = MathHelper.Clamp(element.GetAttributeFloat("revivechancemax", 0.9f), ReviveChanceMin, 1.0f);
|
||||
|
||||
StabilizationPerSkill = Math.Max(element.GetAttributeFloat("stabilizationperskill", 0.01f), 0.0f);
|
||||
StabilizationMin = MathHelper.Max(element.GetAttributeFloat("stabilizationmin", 0.05f), 0.0f);
|
||||
StabilizationMax = MathHelper.Max(element.GetAttributeFloat("stabilizationmax", 2.0f), StabilizationMin);
|
||||
|
||||
DamageSkillThreshold = MathHelper.Clamp(element.GetAttributeFloat("damageskillthreshold", 40.0f), 0.0f, 100.0f);
|
||||
DamageSkillMultiplier = MathHelper.Clamp(element.GetAttributeFloat("damageskillmultiplier", 0.1f), 0.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
class AfflictionPrefab
|
||||
{
|
||||
public class Effect
|
||||
{
|
||||
//this effect is applied when the strength is within this range
|
||||
public float MinStrength, MaxStrength;
|
||||
|
||||
public readonly float MinVitalityDecrease = 0.0f;
|
||||
public readonly float MaxVitalityDecrease = 0.0f;
|
||||
|
||||
//how much the strength of the affliction changes per second
|
||||
public readonly float StrengthChange = 0.0f;
|
||||
|
||||
public readonly bool MultiplyByMaxVitality;
|
||||
|
||||
public float MinScreenBlurStrength, MaxScreenBlurStrength;
|
||||
public float MinScreenDistortStrength, MaxScreenDistortStrength;
|
||||
public float MinRadialDistortStrength, MaxRadialDistortStrength;
|
||||
public float MinChromaticAberrationStrength, MaxChromaticAberrationStrength;
|
||||
|
||||
public string DialogFlag;
|
||||
|
||||
//statuseffects applied on the character when the affliction is active
|
||||
public readonly List<StatusEffect> StatusEffects = new List<StatusEffect>();
|
||||
|
||||
public Effect(XElement element, string parentDebugName)
|
||||
{
|
||||
MinStrength = element.GetAttributeFloat("minstrength", 0);
|
||||
MaxStrength = element.GetAttributeFloat("maxstrength", 0);
|
||||
|
||||
MultiplyByMaxVitality = element.GetAttributeBool("multiplybymaxvitality", false);
|
||||
|
||||
MinVitalityDecrease = element.GetAttributeFloat("minvitalitydecrease", 0.0f);
|
||||
MaxVitalityDecrease = element.GetAttributeFloat("maxvitalitydecrease", 0.0f);
|
||||
MaxVitalityDecrease = Math.Max(MinVitalityDecrease, MaxVitalityDecrease);
|
||||
|
||||
MinScreenDistortStrength = element.GetAttributeFloat("minscreendistort", 0.0f);
|
||||
MaxScreenDistortStrength = element.GetAttributeFloat("maxscreendistort", 0.0f);
|
||||
MaxScreenDistortStrength = Math.Max(MinScreenDistortStrength, MaxScreenDistortStrength);
|
||||
|
||||
MinRadialDistortStrength = element.GetAttributeFloat("minradialdistort", 0.0f);
|
||||
MaxRadialDistortStrength = element.GetAttributeFloat("maxradialdistort", 0.0f);
|
||||
MaxRadialDistortStrength = Math.Max(MinRadialDistortStrength, MaxRadialDistortStrength);
|
||||
|
||||
MinChromaticAberrationStrength = element.GetAttributeFloat("minchromaticaberration", 0.0f);
|
||||
MaxChromaticAberrationStrength = element.GetAttributeFloat("maxchromaticaberration", 0.0f);
|
||||
MaxChromaticAberrationStrength = Math.Max(MinChromaticAberrationStrength, MaxChromaticAberrationStrength);
|
||||
|
||||
MinScreenBlurStrength = element.GetAttributeFloat("minscreenblur", 0.0f);
|
||||
MaxScreenBlurStrength = element.GetAttributeFloat("maxscreenblur", 0.0f);
|
||||
MaxScreenBlurStrength = Math.Max(MinScreenBlurStrength, MaxScreenBlurStrength);
|
||||
|
||||
DialogFlag = element.GetAttributeString("dialogflag", "");
|
||||
|
||||
StrengthChange = element.GetAttributeFloat("strengthchange", 0.0f);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "statuseffect":
|
||||
StatusEffects.Add(StatusEffect.Load(subElement, parentDebugName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AfflictionPrefab InternalDamage;
|
||||
public static AfflictionPrefab Bleeding;
|
||||
public static AfflictionPrefab Burn;
|
||||
public static AfflictionPrefab OxygenLow;
|
||||
public static AfflictionPrefab Bloodloss;
|
||||
public static AfflictionPrefab Pressure;
|
||||
public static AfflictionPrefab Stun;
|
||||
public static AfflictionPrefab Husk;
|
||||
|
||||
public static List<AfflictionPrefab> List = new List<AfflictionPrefab>();
|
||||
|
||||
//Arbitrary string that is used to identify the type of the affliction.
|
||||
//Afflictions with the same type stack up, and items may be configured to cure specific types of afflictions.
|
||||
public readonly string AfflictionType;
|
||||
|
||||
//Does the affliction affect a specific limb or the whole character
|
||||
public readonly bool LimbSpecific;
|
||||
|
||||
//If not a limb-specific affliction, which limb is the indicator shown on in the health menu
|
||||
//(e.g. mental health problems on head, lack of oxygen on torso...)
|
||||
public readonly LimbType IndicatorLimb;
|
||||
|
||||
public readonly string Identifier;
|
||||
|
||||
public readonly string Name, Description;
|
||||
|
||||
public readonly string CauseOfDeathDescription, SelfCauseOfDeathDescription;
|
||||
|
||||
//how high the strength has to be for the affliction to take affect
|
||||
public readonly float ActivationThreshold = 0.0f;
|
||||
//how high the strength has to be for the affliction icon to be shown in the UI
|
||||
public readonly float ShowIconThreshold = 0.0f;
|
||||
public readonly float MaxStrength = 100.0f;
|
||||
|
||||
public float BurnOverlayAlpha;
|
||||
public float DamageOverlayAlpha;
|
||||
|
||||
//steam achievement given when the affliction is removed from the controlled character
|
||||
public readonly string AchievementOnRemoved;
|
||||
|
||||
public readonly Sprite Icon;
|
||||
public readonly Color IconColor;
|
||||
|
||||
private List<Effect> effects = new List<Effect>();
|
||||
|
||||
private Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
|
||||
|
||||
private readonly string typeName;
|
||||
|
||||
private readonly ConstructorInfo constructor;
|
||||
|
||||
public Dictionary<string, float> TreatmentSuitability
|
||||
{
|
||||
get { return treatmentSuitability; }
|
||||
}
|
||||
|
||||
public static void LoadAll(IEnumerable<string> filePaths)
|
||||
{
|
||||
foreach (string filePath in filePaths)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(filePath);
|
||||
if (doc == null || doc.Root == null) continue;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
switch (element.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "internaldamage":
|
||||
List.Add(InternalDamage = new AfflictionPrefab(element, typeof(Affliction)));
|
||||
break;
|
||||
case "bleeding":
|
||||
List.Add(Bleeding = new AfflictionPrefab(element, typeof(AfflictionBleeding)));
|
||||
break;
|
||||
case "burn":
|
||||
List.Add(Burn = new AfflictionPrefab(element, typeof(Affliction)));
|
||||
break;
|
||||
case "oxygenlow":
|
||||
List.Add(OxygenLow = new AfflictionPrefab(element, typeof(Affliction)));
|
||||
break;
|
||||
case "bloodloss":
|
||||
List.Add(Bloodloss = new AfflictionPrefab(element, typeof(Affliction)));
|
||||
break;
|
||||
case "pressure":
|
||||
List.Add(Pressure = new AfflictionPrefab(element, typeof(Affliction)));
|
||||
break;
|
||||
case "stun":
|
||||
List.Add(Stun = new AfflictionPrefab(element, typeof(Affliction)));
|
||||
break;
|
||||
case "husk":
|
||||
case "afflictionhusk":
|
||||
List.Add(Husk = new AfflictionPrefab(element, typeof(AfflictionHusk)));
|
||||
break;
|
||||
case "cprsettings":
|
||||
CPRSettings.Load(element);
|
||||
break;
|
||||
default:
|
||||
List.Add(new AfflictionPrefab(element));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (InternalDamage == null) DebugConsole.ThrowError("Affliction \"Internal Damage\" not defined in the affliction prefabs.");
|
||||
if (Bleeding == null) DebugConsole.ThrowError("Affliction \"Bleeding\" not defined in the affliction prefabs.");
|
||||
if (Burn == null) DebugConsole.ThrowError("Affliction \"Burn\" not defined in the affliction prefabs.");
|
||||
if (OxygenLow == null) DebugConsole.ThrowError("Affliction \"OxygenLow\" not defined in the affliction prefabs.");
|
||||
if (Bloodloss == null) DebugConsole.ThrowError("Affliction \"Bloodloss\" not defined in the affliction prefabs.");
|
||||
if (Pressure == null) DebugConsole.ThrowError("Affliction \"Pressure\" not defined in the affliction prefabs.");
|
||||
if (Stun == null) DebugConsole.ThrowError("Affliction \"Stun\" not defined in the affliction prefabs.");
|
||||
if (Husk == null) DebugConsole.ThrowError("Affliction \"Husk\" not defined in the affliction prefabs.");
|
||||
}
|
||||
|
||||
public AfflictionPrefab(XElement element, Type type = null)
|
||||
{
|
||||
typeName = type == null ? element.Name.ToString() : type.Name;
|
||||
|
||||
Identifier = element.GetAttributeString("identifier", "");
|
||||
|
||||
AfflictionType = element.GetAttributeString("type", "");
|
||||
Name = TextManager.Get("AfflictionName." + Identifier, true) ?? element.GetAttributeString("name", "");
|
||||
Description = TextManager.Get("AfflictionDescription." + Identifier, true) ?? element.GetAttributeString("description", "");
|
||||
|
||||
LimbSpecific = element.GetAttributeBool("limbspecific", false);
|
||||
if (!LimbSpecific)
|
||||
{
|
||||
string indicatorLimbName = element.GetAttributeString("indicatorlimb", "Torso");
|
||||
if (!Enum.TryParse(indicatorLimbName, out IndicatorLimb))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in affliction prefab " + Name + " - limb type \"" + indicatorLimbName + "\" not found.");
|
||||
}
|
||||
}
|
||||
|
||||
ActivationThreshold = element.GetAttributeFloat("activationthreshold", 0.0f);
|
||||
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", ActivationThreshold);
|
||||
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
|
||||
|
||||
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
|
||||
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
|
||||
|
||||
CauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeath." + Identifier, true) ?? element.GetAttributeString("causeofdeathdescription", "");
|
||||
SelfCauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeathSelf." + Identifier, true) ?? element.GetAttributeString("selfcauseofdeathdescription", "");
|
||||
|
||||
AchievementOnRemoved = element.GetAttributeString("achievementonremoved", "");
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "icon":
|
||||
Icon = new Sprite(subElement);
|
||||
IconColor = subElement.GetAttributeColor("color", Color.White);
|
||||
break;
|
||||
case "effect":
|
||||
effects.Add(new Effect(subElement, Name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
type = Type.GetType("Barotrauma." + typeName, true, true);
|
||||
if (type == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find an affliction class of the type \"" + typeName + "\".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find an affliction class of the type \"" + typeName + "\".");
|
||||
return;
|
||||
}
|
||||
|
||||
constructor = type.GetConstructor(new[] { typeof(AfflictionPrefab), typeof(float) });
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "AfflictionPrefab (" + Name + ")";
|
||||
}
|
||||
|
||||
public Affliction Instantiate(float strength, Character source = null)
|
||||
{
|
||||
object instance = null;
|
||||
try
|
||||
{
|
||||
instance = constructor.Invoke(new object[] { this, strength });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugConsole.ThrowError(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString());
|
||||
}
|
||||
Affliction affliction = instance as Affliction;
|
||||
affliction.Source = source;
|
||||
return affliction;
|
||||
}
|
||||
|
||||
public Effect GetActiveEffect(float currentStrength)
|
||||
{
|
||||
foreach (Effect effect in effects)
|
||||
{
|
||||
if (currentStrength > effect.MinStrength && currentStrength <= effect.MaxStrength) return effect;
|
||||
}
|
||||
|
||||
//if above the strength range of all effects, use the highest strength effect
|
||||
Effect strongestEffect = null;
|
||||
float largestStrength = currentStrength;
|
||||
foreach (Effect effect in effects)
|
||||
{
|
||||
if (currentStrength > effect.MaxStrength &&
|
||||
(strongestEffect == null || effect.MaxStrength > largestStrength))
|
||||
{
|
||||
strongestEffect = effect;
|
||||
largestStrength = effect.MaxStrength;
|
||||
}
|
||||
}
|
||||
return strongestEffect;
|
||||
}
|
||||
|
||||
public float GetTreatmentSuitability(Item item)
|
||||
{
|
||||
if (item == null || !treatmentSuitability.ContainsKey(item.Prefab.Identifier.ToLowerInvariant()))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return treatmentSuitability[item.Prefab.Identifier.ToLowerInvariant()];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Xml.Linq;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AfflictionPsychosis : Affliction
|
||||
{
|
||||
|
||||
public AfflictionPsychosis(AfflictionPrefab prefab, float strength) : base(prefab, strength)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
|
||||
{
|
||||
base.Update(characterHealth, targetLimb, deltaTime);
|
||||
UpdateProjSpecific(characterHealth, targetLimb, deltaTime);
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime);
|
||||
}
|
||||
}
|
||||
@@ -739,7 +739,7 @@ namespace Barotrauma
|
||||
msg.Write((byte)activeAfflictions.Count);
|
||||
foreach (Affliction affliction in activeAfflictions)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(affliction.Prefab));
|
||||
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(affliction.Prefab), 0, AfflictionPrefab.List.Count - 1);
|
||||
msg.WriteRangedSingle(
|
||||
MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength),
|
||||
0.0f, affliction.Prefab.MaxStrength, 8);
|
||||
@@ -758,8 +758,8 @@ namespace Barotrauma
|
||||
msg.Write((byte)limbAfflictions.Count);
|
||||
foreach (var limbAffliction in limbAfflictions)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, limbHealths.Count - 1, limbHealths.IndexOf(limbAffliction.First));
|
||||
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab));
|
||||
msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1);
|
||||
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab), 0, AfflictionPrefab.List.Count - 1);
|
||||
msg.WriteRangedSingle(
|
||||
MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength),
|
||||
0.0f, limbAffliction.Second.Prefab.MaxStrength, 8);
|
||||
|
||||
@@ -90,6 +90,7 @@ namespace Barotrauma.Items.Components
|
||||
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
|
||||
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall;
|
||||
item.body.FarseerBody.OnCollision += OnCollision;
|
||||
item.body.FarseerBody.IsBullet = true;
|
||||
|
||||
if (!character.AnimController.InWater)
|
||||
{
|
||||
@@ -207,9 +208,9 @@ namespace Barotrauma.Items.Components
|
||||
private void RestoreCollision()
|
||||
{
|
||||
item.body.FarseerBody.OnCollision -= OnCollision;
|
||||
|
||||
item.body.CollisionCategories = Physics.CollisionItem;
|
||||
item.body.CollidesWith = Physics.CollisionWall;
|
||||
item.body.FarseerBody.IsBullet = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
if (character.AnimController.InWater)
|
||||
if (item.InWater)
|
||||
{
|
||||
if (UsableIn == UseEnvironment.Air)
|
||||
{
|
||||
@@ -160,7 +160,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
rayStart = ConvertUnits.ToSimUnits(item.WorldPosition);
|
||||
rayStart = Submarine.LastPickedPosition + Submarine.LastPickedNormal * 0.1f;
|
||||
if (item.Submarine != null) { rayStart += item.Submarine.SimPosition; }
|
||||
}
|
||||
|
||||
Vector2 rayEnd = rayStart +
|
||||
@@ -201,12 +202,12 @@ namespace Barotrauma.Items.Components
|
||||
Repair(rayStart - character.Submarine.SimPosition, rayEnd - character.Submarine.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies);
|
||||
}
|
||||
|
||||
UseProjSpecific(deltaTime);
|
||||
UseProjSpecific(deltaTime, rayStart);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
partial void UseProjSpecific(float deltaTime);
|
||||
partial void UseProjSpecific(float deltaTime, Vector2 raystart);
|
||||
|
||||
private readonly HashSet<Character> hitCharacters = new HashSet<Character>();
|
||||
private readonly List<FireSource> fireSourcesInRange = new List<FireSource>();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FarseerPhysics;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,7 +20,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
partial class Controller : ItemComponent
|
||||
partial class Controller : ItemComponent, IServerSerializable
|
||||
{
|
||||
//where the limbs of the user should be positioned when using the controller
|
||||
private List<LimbPos> limbPositions;
|
||||
@@ -270,17 +271,21 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (IsToggle)
|
||||
{
|
||||
state = !state;
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
state = !state;
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SendSignal(0, "1", "signal_out", picker);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
PlaySound(ActionType.OnUse, item.WorldPosition, picker);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,14 +273,18 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (connection.Name == "set_rate")
|
||||
{
|
||||
float tempSpeed;
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out tempSpeed))
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
|
||||
{
|
||||
if (!MathUtils.IsValid(tempSpeed)) return;
|
||||
RechargeSpeed = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f) * MaxRechargeSpeed;
|
||||
if (!MathUtils.IsValid(tempSpeed)) { return; }
|
||||
|
||||
float rechargeRate = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f);
|
||||
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
|
||||
#if CLIENT
|
||||
rechargeSpeedSlider.BarScroll = rechargeRate;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (!connection.IsPower) return;
|
||||
if (!connection.IsPower) { return; }
|
||||
|
||||
if (connection.Name == "power_in")
|
||||
{
|
||||
|
||||
@@ -146,6 +146,10 @@ namespace Barotrauma.Items.Components
|
||||
currentFixerAction = FixActions.None;
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
#if CLIENT
|
||||
repairSoundChannel?.FadeOutAndDispose();
|
||||
repairSoundChannel = null;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -221,8 +225,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
float successFactor = requiredSkills.Count == 0 ? 1.0f : 0.0f;
|
||||
|
||||
float successFactor = requiredSkills.Count == 0 ? 1.0f : DegreeOfSuccess(CurrentFixer, requiredSkills);
|
||||
|
||||
//item must have been below the repair threshold for the player to get an achievement or XP for repairing it
|
||||
if (item.ConditionPercentage < ShowRepairUIThreshold)
|
||||
{
|
||||
|
||||
@@ -122,22 +122,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
#if CLIENT
|
||||
foreach (Wire wire in DisconnectedWires)
|
||||
{
|
||||
if (Rand.Range(0.0f, 500.0f) < 1.0f)
|
||||
{
|
||||
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
Vector2 baseVel = new Vector2(0.0f, -100.0f);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
|
||||
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
|
||||
if (particle != null) { particle.Size *= Rand.Range(0.5f, 1.0f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
UpdateProjSpecific(deltaTime);
|
||||
|
||||
if (user == null || user.SelectedConstruction != item)
|
||||
{
|
||||
@@ -150,6 +135,8 @@ namespace Barotrauma.Items.Components
|
||||
user.AnimController.UpdateUseItem(true, item.WorldPosition + new Vector2(0.0f, 100.0f) * (((float)Timing.TotalTime / 10.0f) % 0.1f));
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
public override bool Select(Character picker)
|
||||
{
|
||||
//attaching wires to items with a body is not allowed
|
||||
@@ -260,8 +247,14 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
rewireSoundChannel?.FadeOutAndDispose();
|
||||
rewireSoundChannel = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
foreach (Connection connection in Connections)
|
||||
|
||||
@@ -160,6 +160,14 @@ namespace Barotrauma.Items.Components
|
||||
item.AddTag("light");
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
public override void OnScaleChanged()
|
||||
{
|
||||
light.SpriteScale = Vector2.One * item.Scale;
|
||||
light.Position = ParentBody != null ? ParentBody.Position : item.Position;
|
||||
}
|
||||
#endif
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
@@ -175,7 +183,6 @@ namespace Barotrauma.Items.Components
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
|
||||
#if CLIENT
|
||||
light.SpriteScale = Vector2.One * item.Scale;
|
||||
light.ParentSub = item.Submarine;
|
||||
if (item.Container != null)
|
||||
{
|
||||
|
||||
@@ -336,30 +336,39 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Item FindItemByTag(string tag)
|
||||
public Item FindItem(Func<Item, bool> predicate, bool recursive)
|
||||
{
|
||||
if (tag == null) return null;
|
||||
return Items.FirstOrDefault(i => i != null && i.HasTag(tag));
|
||||
Item match = Items.FirstOrDefault(predicate);
|
||||
if (match == null && recursive)
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
if (item.OwnInventory != null)
|
||||
{
|
||||
match = item.OwnInventory.FindItem(predicate, true);
|
||||
if (match != null)
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
public Item FindItemByIdentifier(string identifier)
|
||||
public Item FindItemByTag(string tag, bool recursive = false)
|
||||
{
|
||||
if (tag == null) { return null; }
|
||||
return FindItem(i => i != null && i.HasTag(tag), recursive);
|
||||
}
|
||||
|
||||
public Item FindItemByIdentifier(string identifier, bool recursive = false)
|
||||
{
|
||||
if (identifier == null) return null;
|
||||
return Items.FirstOrDefault(i => i != null && i.Prefab.Identifier == identifier);
|
||||
return FindItem(i => i != null && i.Prefab.Identifier == identifier, recursive);
|
||||
}
|
||||
|
||||
/*public Item FindItem(string[] itemNames)
|
||||
{
|
||||
if (itemNames == null) return null;
|
||||
|
||||
foreach (string itemName in itemNames)
|
||||
{
|
||||
var item = FindItem(itemName);
|
||||
if (item != null) return item;
|
||||
}
|
||||
return null;
|
||||
}*/
|
||||
|
||||
public virtual void RemoveItem(Item item)
|
||||
{
|
||||
if (item == null) return;
|
||||
@@ -376,6 +385,7 @@ namespace Barotrauma
|
||||
|
||||
public void SharedWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write((byte)capacity);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
msg.Write((ushort)(Items[i] == null ? 0 : Items[i].ID));
|
||||
|
||||
@@ -126,24 +126,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public delegate bool InventoryFilter(Inventory inventory);
|
||||
public Inventory FindParentInventory(InventoryFilter filter)
|
||||
{
|
||||
if (parentInventory != null)
|
||||
{
|
||||
if (filter(parentInventory))
|
||||
{
|
||||
return parentInventory;
|
||||
}
|
||||
var owner = parentInventory.Owner as Item;
|
||||
if (owner != null)
|
||||
{
|
||||
return owner.FindParentInventory(filter);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Item container;
|
||||
public Item Container
|
||||
{
|
||||
@@ -177,6 +159,13 @@ namespace Barotrauma
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable, Serialize(false, true)]
|
||||
public bool NonInteractable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float ImpactTolerance
|
||||
{
|
||||
get { return Prefab.ImpactTolerance; }
|
||||
@@ -398,6 +387,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (!MathUtils.NearlyEqual(lastSentCondition, condition) && (condition <= 0.0f || condition >= Prefab.Health))
|
||||
{
|
||||
sendConditionUpdateTimer = 0.0f;
|
||||
conditionUpdatePending = true;
|
||||
}
|
||||
}
|
||||
@@ -955,7 +945,6 @@ namespace Barotrauma
|
||||
return CurrentHull;
|
||||
}
|
||||
|
||||
|
||||
CurrentHull = Hull.FindHull(WorldPosition, CurrentHull);
|
||||
if (body != null && body.Enabled)
|
||||
{
|
||||
@@ -978,7 +967,23 @@ namespace Barotrauma
|
||||
|
||||
return rootContainer;
|
||||
}
|
||||
|
||||
|
||||
public Inventory FindParentInventory(Func<Inventory, bool> predicate)
|
||||
{
|
||||
if (parentInventory != null)
|
||||
{
|
||||
if (predicate(parentInventory))
|
||||
{
|
||||
return parentInventory;
|
||||
}
|
||||
if (parentInventory.Owner is Item owner)
|
||||
{
|
||||
return owner.FindParentInventory(predicate);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SetContainedItemPositions()
|
||||
{
|
||||
foreach (ItemComponent component in components)
|
||||
@@ -1137,6 +1142,17 @@ namespace Barotrauma
|
||||
return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY;
|
||||
}
|
||||
|
||||
public void SendPendingNetworkUpdates()
|
||||
{
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsServer) { return; }
|
||||
if (conditionUpdatePending)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
lastSentCondition = condition;
|
||||
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
|
||||
conditionUpdatePending = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
@@ -1153,16 +1169,10 @@ namespace Barotrauma
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
sendConditionUpdateTimer -= deltaTime;
|
||||
if (conditionUpdatePending)
|
||||
if (conditionUpdatePending && sendConditionUpdateTimer <= 0.0f)
|
||||
{
|
||||
if (sendConditionUpdateTimer <= 0.0f)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||
lastSentCondition = condition;
|
||||
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
|
||||
conditionUpdatePending = false;
|
||||
}
|
||||
}
|
||||
SendPendingNetworkUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.Always, deltaTime, null);
|
||||
@@ -1878,7 +1888,7 @@ namespace Barotrauma
|
||||
var propertyOwner = allProperties.Find(p => p.Second == property);
|
||||
if (allProperties.Count > 1)
|
||||
{
|
||||
msg.WriteRangedIntegerDeprecated(0, allProperties.Count - 1, allProperties.FindIndex(p => p.Second == property));
|
||||
msg.WriteRangedInteger(allProperties.FindIndex(p => p.Second == property), 0, allProperties.Count - 1);
|
||||
}
|
||||
|
||||
object value = property.GetValue(propertyOwner.First);
|
||||
@@ -2141,7 +2151,8 @@ namespace Barotrauma
|
||||
if (element.GetAttributeBool("flippedx", false)) item.FlipX(false);
|
||||
if (element.GetAttributeBool("flippedy", false)) item.FlipY(false);
|
||||
|
||||
item.condition = element.GetAttributeFloat("condition", item.Prefab.Health);
|
||||
float condition = element.GetAttributeFloat("condition", item.MaxCondition);
|
||||
item.condition = MathHelper.Clamp(condition, 0, item.MaxCondition);
|
||||
item.lastSentCondition = item.condition;
|
||||
|
||||
item.SetActiveSprite();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -92,10 +93,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Item.ItemList.Contains(container.Item))
|
||||
{
|
||||
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.";
|
||||
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
|
||||
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,7 @@ namespace Barotrauma
|
||||
{
|
||||
private readonly XElement configElement;
|
||||
private readonly string configPath;
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool HideInMenus { get; set; }
|
||||
|
||||
|
||||
public List<Pair<MapEntityPrefab, Rectangle>> DisplayEntities
|
||||
{
|
||||
get;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user