Unstable 0.16.1.0
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
namespace Barotrauma
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract partial class AIObjective
|
||||
{
|
||||
public static Color ObjectiveIconColor => Color.LightGray;
|
||||
|
||||
public static Sprite GetSprite(string identifier, string option, Entity targetEntity)
|
||||
{
|
||||
if (string.IsNullOrEmpty(identifier))
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Barotrauma
|
||||
|
||||
public bool PlaySound;
|
||||
|
||||
public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null)
|
||||
public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null, float lifeTime = 3.0f)
|
||||
{
|
||||
RawText = Text = rawText;
|
||||
if (value.HasValue)
|
||||
@@ -166,7 +166,7 @@ namespace Barotrauma
|
||||
Size = GUI.Font.MeasureString(Text);
|
||||
Color = color;
|
||||
Identifier = identifier;
|
||||
Lifetime = 3.0f;
|
||||
Lifetime = lifeTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -997,7 +997,7 @@ namespace Barotrauma
|
||||
return nameColor;
|
||||
}
|
||||
|
||||
public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null)
|
||||
public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null, float lifetime = 3.0f)
|
||||
{
|
||||
GUIMessage existingMessage = null;
|
||||
|
||||
@@ -1026,7 +1026,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (existingMessage == null || !value.HasValue)
|
||||
{
|
||||
var newMessage = new GUIMessage(rawText, color, delay, identifier, value);
|
||||
var newMessage = new GUIMessage(rawText, color, delay, identifier, value, lifetime);
|
||||
guiMessages.Insert(0, newMessage);
|
||||
if (playSound)
|
||||
{
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Barotrauma
|
||||
|
||||
return
|
||||
character?.Inventory != null &&
|
||||
character.AllowInput &&
|
||||
!character.Removed && !character.IsKnockedDown &&
|
||||
(controller?.User != character || !controller.HideHUD) &&
|
||||
!IsCampaignInterfaceOpen &&
|
||||
!ConversationAction.FadeScreenToBlack;
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Barotrauma
|
||||
private static Sprite infoAreaPortraitBG;
|
||||
|
||||
public bool LastControlled;
|
||||
public int CrewListIndex { get; set; } = -1;
|
||||
|
||||
#warning TODO: Refactor
|
||||
private Sprite disguisedPortrait;
|
||||
@@ -831,7 +832,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
new GUIFrame(
|
||||
new RectTransform(new Vector2(1.25f, 1.25f), HeadSelectionList.RectTransform, Anchor.Center),
|
||||
new RectTransform(new Vector2(1.25f, 1.25f), HeadSelectionList.ContentBackground.RectTransform, Anchor.Center),
|
||||
style: "OuterGlow", color: Color.Black)
|
||||
{
|
||||
UserData = "outerglow",
|
||||
@@ -966,10 +967,15 @@ namespace Barotrauma
|
||||
foreach (Sprite sprite in characterSprites) { sprite.Remove(); }
|
||||
characterSprites.Clear();
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ClearSprites();
|
||||
if (HeadSelectionList != null)
|
||||
{
|
||||
HeadSelectionList.RectTransform.Parent = null;
|
||||
HeadSelectionList = null;
|
||||
}
|
||||
}
|
||||
|
||||
~AppearanceCustomizationMenu()
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Barotrauma
|
||||
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
|
||||
if (fireHull != null)
|
||||
{
|
||||
var fakeFire = new DummyFireSource(Vector2.One * 500.0f, new Vector2(Rand.Range(fireHull.WorldRect.X, fireHull.WorldRect.Right), fireHull.WorldPosition.Y), fireHull, isNetworkMessage: true)
|
||||
var fakeFire = new DummyFireSource(Vector2.One * 500.0f, new Vector2(Rand.Range(fireHull.WorldRect.X, fireHull.WorldRect.Right), fireHull.WorldPosition.Y + 1), fireHull, isNetworkMessage: true)
|
||||
{
|
||||
CausedByPsychosis = true,
|
||||
DamagesItems = false,
|
||||
|
||||
@@ -2018,6 +2018,27 @@ namespace Barotrauma
|
||||
|
||||
limbIndicatorOverlay?.Remove();
|
||||
limbIndicatorOverlay = null;
|
||||
|
||||
if (healthWindow != null)
|
||||
{
|
||||
healthWindow.RectTransform.Parent = null;
|
||||
healthWindow = null;
|
||||
}
|
||||
if (healthBarHolder != null)
|
||||
{
|
||||
healthBarHolder.RectTransform.Parent = null;
|
||||
healthBarHolder = null;
|
||||
}
|
||||
if (SuicideButton != null)
|
||||
{
|
||||
SuicideButton.RectTransform.Parent = null;
|
||||
SuicideButton = null;
|
||||
}
|
||||
if (afflictionTooltip != null)
|
||||
{
|
||||
afflictionTooltip.RectTransform.Parent = null;
|
||||
afflictionTooltip = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,6 +389,12 @@ namespace Barotrauma
|
||||
DrawString(spriteBatch, new Vector2(10, 10),
|
||||
"FPS: " + Math.Round(GameMain.PerformanceCounter.AverageFramesPerSecond),
|
||||
Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
if (GameMain.GameSession != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + 1.0)
|
||||
{
|
||||
DrawString(spriteBatch, new Vector2(10, 25),
|
||||
$"Physics: {GameMain.CurrentUpdateRate}",
|
||||
(GameMain.CurrentUpdateRate < Timing.FixedUpdateRate) ? Color.Red : Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.ShowPerf)
|
||||
@@ -397,7 +403,7 @@ namespace Barotrauma
|
||||
DrawString(spriteBatch, new Vector2(300, y),
|
||||
"Draw - Avg: " + GameMain.PerformanceCounter.DrawTimeGraph.Average().ToString("0.00") + " ms" +
|
||||
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
|
||||
GUI.Style.Green, Color.Black * 0.8f, font: SmallFont);
|
||||
Style.Green, Color.Black * 0.8f, font: SmallFont);
|
||||
y += 15;
|
||||
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Style.Green);
|
||||
y += 50;
|
||||
@@ -408,7 +414,6 @@ namespace Barotrauma
|
||||
Color.LightBlue, Color.Black * 0.8f, font: SmallFont);
|
||||
y += 15;
|
||||
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Color.LightBlue);
|
||||
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), maxValue: 20, color: Style.Red);
|
||||
y += 50;
|
||||
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
|
||||
{
|
||||
@@ -431,7 +436,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
if (GameMain.DebugDraw && !Submarine.Unloading && !(Screen.Selected is RoundSummaryScreen))
|
||||
{
|
||||
DrawString(spriteBatch, new Vector2(10, 25),
|
||||
"Physics: " + GameMain.World.UpdateTime,
|
||||
@@ -2435,6 +2440,11 @@ namespace Barotrauma
|
||||
private static bool TogglePauseMenu(GUIButton button, object obj)
|
||||
{
|
||||
pauseMenuOpen = !pauseMenuOpen;
|
||||
if (!pauseMenuOpen && PauseMenu != null)
|
||||
{
|
||||
PauseMenu.RectTransform.Parent = null;
|
||||
PauseMenu = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,14 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Instance.ResolutionChanged += RecalculateSize;
|
||||
}
|
||||
_instance.ItemComponentHolder = new GUIFrame(new RectTransform(Vector2.One, _instance, Anchor.Center)).RectTransform;
|
||||
_instance.ChildrenChanged += OnChildrenChanged;
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public RectTransform ItemComponentHolder;
|
||||
//GUICanvas stores the children as weak references, to allow elements that we no longer need to get garbage collected
|
||||
private readonly List<WeakReference<RectTransform>> childrenWeakRef = new List<WeakReference<RectTransform>>();
|
||||
|
||||
private static Vector2 size => new Vector2(GameMain.GraphicsWidth / (float)GUI.UIWidth, 1f);
|
||||
|
||||
@@ -36,16 +37,41 @@ namespace Barotrauma
|
||||
|
||||
private enum ResizeAxis { Both = 0, X = 1, Y = 2 }
|
||||
|
||||
private static void OnChildrenChanged(RectTransform _)
|
||||
{
|
||||
//add weak reference if we don't have one yet
|
||||
foreach (var child in _instance.Children)
|
||||
{
|
||||
if (!_instance.childrenWeakRef.Any(c => c.TryGetTarget(out var existingChild) && existingChild == child))
|
||||
{
|
||||
_instance.childrenWeakRef.Add(new WeakReference<RectTransform>(child));
|
||||
}
|
||||
}
|
||||
//get rid of strong references
|
||||
_instance.children.Clear();
|
||||
//remove dead children
|
||||
for (int i = _instance.childrenWeakRef.Count - 2; i >= 0; i--)
|
||||
{
|
||||
if (!_instance.childrenWeakRef[i].TryGetTarget(out var child) || child.Parent != _instance)
|
||||
{
|
||||
_instance.childrenWeakRef.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn public, if there is a need to call this manually.
|
||||
private static void RecalculateSize()
|
||||
{
|
||||
Vector2 recalculatedSize = size;
|
||||
|
||||
// Scale children that are supposed to encompass the whole screen so that they are properly scaled on ultrawide as well
|
||||
for (int i = 0; i < Instance.Children.Count(); i++)
|
||||
for (int i = 0; i < Instance.childrenWeakRef.Count; i++)
|
||||
{
|
||||
RectTransform target = Instance.GetChild(i);
|
||||
if (target == null || target.RelativeSize.X < 1 && target.RelativeSize.Y < 1) continue;
|
||||
if (!_instance.childrenWeakRef[i].TryGetTarget(out RectTransform target) || target == null) { continue; };
|
||||
|
||||
_instance.children.Add(target);
|
||||
|
||||
if (target.RelativeSize.X < 1 && target.RelativeSize.Y < 1) { continue; }
|
||||
|
||||
ResizeAxis axis;
|
||||
|
||||
@@ -80,6 +106,7 @@ namespace Barotrauma
|
||||
|
||||
Instance.Resize(size, resizeChildren: true);
|
||||
Instance.GetAllChildren().Select(c => c.GUIComponent as GUITextBlock).ForEach(t => t?.SetTextPos());
|
||||
_instance.children.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +362,14 @@ namespace Barotrauma
|
||||
RectTransform.ScaleChanged += () => dimensionsNeedsRecalculation = true;
|
||||
RectTransform.SizeChanged += () => dimensionsNeedsRecalculation = true;
|
||||
UpdateDimensions();
|
||||
|
||||
rectT.ChildrenChanged += CheckForChildren;
|
||||
}
|
||||
|
||||
private void CheckForChildren(RectTransform rectT)
|
||||
{
|
||||
if (rectT == ScrollBar.RectTransform || rectT == Content.RectTransform || rectT == ContentBackground.RectTransform) { return; }
|
||||
throw new InvalidOperationException($"Children were added to {nameof(GUIListBox)}, Add them to {nameof(GUIListBox)}.{nameof(Content)} instead.");
|
||||
}
|
||||
|
||||
public void UpdateDimensions()
|
||||
@@ -827,13 +835,6 @@ namespace Barotrauma
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
if (child == ScrollBar || child == Content || child == ContentBackground) { continue; }
|
||||
|
||||
throw new InvalidOperationException($"Children were found in {nameof(GUIListBox)}, Add them to {nameof(GUIListBox)}.{nameof(Content)} instead.");
|
||||
}
|
||||
|
||||
if (!Visible) { return; }
|
||||
|
||||
UpdateChildrenRect();
|
||||
|
||||
@@ -618,6 +618,7 @@ namespace Barotrauma
|
||||
|
||||
public bool Close(GUIButton button, object obj)
|
||||
{
|
||||
RectTransform.Parent = null;
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ namespace Barotrauma
|
||||
// sum up all the afflictions and their strengths
|
||||
Dictionary<AfflictionPrefab, float> afflictionAndStrength = new Dictionary<AfflictionPrefab, float>();
|
||||
|
||||
foreach (Affliction affliction in health.GetAllAfflictions().Where(a => !a.Prefab.IsBuff && a.Strength > 0))
|
||||
foreach (Affliction affliction in health.GetAllAfflictions().Where(a => MedicalClinic.IsHealable(a)))
|
||||
{
|
||||
if (afflictionAndStrength.TryGetValue(affliction.Prefab, out float strength))
|
||||
{
|
||||
@@ -581,7 +581,6 @@ namespace Barotrauma
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
button.Enabled = false;
|
||||
ClosePopup();
|
||||
medicalClinic.HealAllButtonAction(request =>
|
||||
{
|
||||
switch (request.HealResult)
|
||||
@@ -595,7 +594,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
button.Enabled = true;
|
||||
ClosePopup();
|
||||
});
|
||||
ClosePopup();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -993,7 +994,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void ClosePopup()
|
||||
public void ClosePopup()
|
||||
{
|
||||
if (selectedCrewElement is { } popup)
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<RectTransform> children = new List<RectTransform>();
|
||||
protected readonly List<RectTransform> children = new List<RectTransform>();
|
||||
public IEnumerable<RectTransform> Children => children;
|
||||
|
||||
public int CountChildren => children.Count;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
public enum InfoFrameTab { Crew, Mission, Reputation, Traitor, Submarine, Talents };
|
||||
public static InfoFrameTab selectedTab;
|
||||
public static InfoFrameTab SelectedTab { get; private set; }
|
||||
private GUIFrame infoFrame, contentFrame;
|
||||
|
||||
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
|
||||
@@ -130,8 +130,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (!initialized) { Initialize(); }
|
||||
|
||||
CreateInfoFrame(selectedTab);
|
||||
SelectInfoFrameTab(null, selectedTab);
|
||||
CreateInfoFrame(SelectedTab);
|
||||
SelectInfoFrameTab(SelectedTab);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
@@ -147,8 +147,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTab != InfoFrameTab.Crew) return;
|
||||
if (linkedGUIList == null) return;
|
||||
if (SelectedTab != InfoFrameTab.Crew) { return; }
|
||||
if (linkedGUIList == null) { return; }
|
||||
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
@@ -226,7 +226,7 @@ namespace Barotrauma
|
||||
{
|
||||
UserData = tab,
|
||||
ToolTip = TextManager.Get(textTag),
|
||||
OnClicked = SelectInfoFrameTab
|
||||
OnClicked = (btn, userData) => { SelectInfoFrameTab((InfoFrameTab)userData); return true; }
|
||||
};
|
||||
tabButtons.Add(newButton);
|
||||
return newButton;
|
||||
@@ -277,16 +277,16 @@ namespace Barotrauma
|
||||
talentsButton.Enabled = Character.Controlled?.Info != null;
|
||||
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
||||
{
|
||||
SelectInfoFrameTab(null, InfoFrameTab.Crew);
|
||||
SelectInfoFrameTab(InfoFrameTab.Crew);
|
||||
}
|
||||
};
|
||||
|
||||
talentPointNotification = GameSession.CreateTalentIconNotification(talentsButton);
|
||||
}
|
||||
|
||||
private bool SelectInfoFrameTab(GUIButton button, object userData)
|
||||
public void SelectInfoFrameTab(InfoFrameTab selectedTab)
|
||||
{
|
||||
selectedTab = (InfoFrameTab)userData;
|
||||
SelectedTab = selectedTab;
|
||||
|
||||
CreateInfoFrame(selectedTab);
|
||||
tabButtons.ForEach(tb => tb.Selected = (InfoFrameTab)tb.UserData == selectedTab);
|
||||
@@ -310,7 +310,7 @@ namespace Barotrauma
|
||||
case InfoFrameTab.Traitor:
|
||||
TraitorMissionPrefab traitorMission = GameMain.Client.TraitorMission;
|
||||
Character traitor = GameMain.Client.Character;
|
||||
if (traitor == null || traitorMission == null) return false;
|
||||
if (traitor == null || traitorMission == null) { return; }
|
||||
CreateTraitorInfo(infoFrameHolder, traitorMission, traitor);
|
||||
break;
|
||||
case InfoFrameTab.Submarine:
|
||||
@@ -320,8 +320,6 @@ namespace Barotrauma
|
||||
CreateTalentInfo(infoFrameHolder);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private const float jobColumnWidthPercentage = 0.138f;
|
||||
@@ -859,7 +857,7 @@ namespace Barotrauma
|
||||
string msg = ChatMessage.GetTimeStamp() + message.TextWithSender;
|
||||
storedMessages.Add(new Pair<string, PlayerConnectionChangeType>(msg, message.ChangeType));
|
||||
|
||||
if (GameSession.IsTabMenuOpen && selectedTab == InfoFrameTab.Crew)
|
||||
if (GameSession.IsTabMenuOpen && SelectedTab == InfoFrameTab.Crew)
|
||||
{
|
||||
TabMenu instance = GameSession.TabMenuInstance;
|
||||
instance.AddLineToLog(msg, message.ChangeType);
|
||||
|
||||
@@ -433,6 +433,7 @@ namespace Barotrauma
|
||||
if (AvailableMoney >= hullRepairCost)
|
||||
{
|
||||
Campaign.Money -= hullRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
Campaign.PurchasedHullRepairs = true;
|
||||
button.Enabled = false;
|
||||
SelectTab(UpgradeTab.Repairs);
|
||||
@@ -467,6 +468,7 @@ namespace Barotrauma
|
||||
if (AvailableMoney >= itemRepairCost && !Campaign.PurchasedItemRepairs)
|
||||
{
|
||||
Campaign.Money -= itemRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
Campaign.PurchasedItemRepairs = true;
|
||||
button.Enabled = false;
|
||||
SelectTab(UpgradeTab.Repairs);
|
||||
@@ -512,6 +514,7 @@ namespace Barotrauma
|
||||
if (AvailableMoney >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
|
||||
{
|
||||
Campaign.Money -= shuttleRetrieveCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
|
||||
Campaign.PurchasedLostShuttles = true;
|
||||
button.Enabled = false;
|
||||
SelectTab(UpgradeTab.Repairs);
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static partial class GameAnalyticsManager
|
||||
static partial class GameAnalyticsManager
|
||||
{
|
||||
static partial void CreateConsentPrompt()
|
||||
{
|
||||
|
||||
@@ -30,6 +30,13 @@ namespace Barotrauma
|
||||
|
||||
public static PerformanceCounter PerformanceCounter;
|
||||
|
||||
private static Stopwatch performanceCounterTimer;
|
||||
private static int updateCount = 0;
|
||||
public static int CurrentUpdateRate
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
public static string[] ConsoleArguments;
|
||||
@@ -122,6 +129,12 @@ namespace Barotrauma
|
||||
|
||||
private bool exiting;
|
||||
|
||||
public static bool IsFirstLaunch
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static GameMain Instance
|
||||
{
|
||||
get;
|
||||
@@ -349,6 +362,8 @@ namespace Barotrauma
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Item));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Items.Components.ItemComponent));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
|
||||
|
||||
performanceCounterTimer = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -579,6 +594,18 @@ namespace Barotrauma
|
||||
{
|
||||
Steamworks.SteamFriends.OnGameRichPresenceJoinRequested += OnInvitedToGame;
|
||||
Steamworks.SteamFriends.OnGameLobbyJoinRequested += OnLobbyJoinRequested;
|
||||
|
||||
if (SteamManager.TryGetUnlockedAchievements(out List<Steamworks.Data.Achievement> achievements))
|
||||
{
|
||||
//check the achievements too, so we don't consider people who've played the game before this "gamelaunchcount" stat was added as being 1st-time-players
|
||||
//(people who have played previous versions, but not unlocked any achievements, will be incorrectly considered 1st-time-players, but that should be a small enough group to not skew the statistics)
|
||||
if (!achievements.Any() && SteamManager.GetStatInt("gamelaunchcount") <= 0)
|
||||
{
|
||||
IsFirstLaunch = true;
|
||||
GameAnalyticsManager.AddDesignEvent("FirstLaunch");
|
||||
}
|
||||
}
|
||||
SteamManager.IncrementStat("gamelaunchcount", 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -696,11 +723,10 @@ namespace Barotrauma
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
Timing.Accumulator += gameTime.ElapsedGameTime.TotalSeconds;
|
||||
int updateIterations = (int)Math.Floor(Timing.Accumulator / Timing.Step);
|
||||
if (Timing.Accumulator > Timing.Step * 6.0)
|
||||
if (Timing.Accumulator > Timing.AccumulatorMax)
|
||||
{
|
||||
//if the game's running too slowly then we have no choice
|
||||
//but to skip a bunch of steps
|
||||
//prevent spiral of death:
|
||||
//if the game's running too slowly then we have no choice but to skip a bunch of steps
|
||||
//otherwise it snowballs and becomes unplayable
|
||||
Timing.Accumulator = Timing.Step;
|
||||
}
|
||||
@@ -736,7 +762,6 @@ namespace Barotrauma
|
||||
|
||||
PlayerInput.Update(Timing.Step);
|
||||
|
||||
|
||||
if (loadingScreenOpen)
|
||||
{
|
||||
//reset accumulator if loading
|
||||
@@ -975,13 +1000,21 @@ namespace Barotrauma
|
||||
|
||||
Timing.Accumulator -= Timing.Step;
|
||||
|
||||
updateCount++;
|
||||
|
||||
sw.Stop();
|
||||
PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks);
|
||||
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
||||
PerformanceCounter.UpdateIterationsGraph.Update(updateIterations);
|
||||
}
|
||||
|
||||
if (!Paused) Timing.Alpha = Timing.Accumulator / Timing.Step;
|
||||
if (!Paused) { Timing.Alpha = Timing.Accumulator / Timing.Step; }
|
||||
|
||||
if (performanceCounterTimer.ElapsedMilliseconds > 1000)
|
||||
{
|
||||
CurrentUpdateRate = (int)Math.Round(updateCount / (double)(performanceCounterTimer.ElapsedMilliseconds / 1000.0));
|
||||
performanceCounterTimer.Restart();
|
||||
updateCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResetFrameTime()
|
||||
@@ -1086,8 +1119,15 @@ namespace Barotrauma
|
||||
{
|
||||
double roundDuration = Timing.TotalTime - GameSession.RoundStartTime;
|
||||
GameAnalyticsManager.AddProgressionEvent(GameAnalyticsManager.ProgressionStatus.Fail,
|
||||
GameSession.GameMode?.Name ?? "none",
|
||||
GameSession.GameMode?.Preset.Identifier ?? "none",
|
||||
roundDuration);
|
||||
string eventId = "QuitRound:" + (GameSession.GameMode?.Preset.Identifier ?? "none") + ":";
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:CurrentIntensity", GameSession.EventManager.CurrentIntensity);
|
||||
foreach (var activeEvent in GameSession.EventManager.ActiveEvents)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "EventManager:ActiveEvents:" + activeEvent.ToString());
|
||||
}
|
||||
GameSession.LogEndRoundStats(eventId);
|
||||
if (Tutorial.Initialized)
|
||||
{
|
||||
((TutorialMode)GameSession.GameMode).Tutorial?.Stop();
|
||||
|
||||
@@ -232,6 +232,8 @@ namespace Barotrauma
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier);
|
||||
|
||||
// Remove from the sell crate
|
||||
// TODO: Simplify duplicate logic?
|
||||
if (sellingMode == Store.StoreTab.Sell && ItemsInSellCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } inventoryItem)
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
|
||||
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), null, Color.Transparent)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
@@ -302,7 +302,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
/// <param name="character">The character to remove</param>
|
||||
/// <param name="removeInfo">If the character info is also removed, the character will not be visible in the round summary.</param>
|
||||
public void RemoveCharacter(Character character, bool removeInfo = false)
|
||||
public void RemoveCharacter(Character character, bool removeInfo = false, bool resetCrewListIndex = true)
|
||||
{
|
||||
if (character == null)
|
||||
{
|
||||
@@ -311,14 +311,15 @@ namespace Barotrauma
|
||||
}
|
||||
characters.Remove(character);
|
||||
if (removeInfo) { characterInfos.Remove(character.Info); }
|
||||
if (resetCrewListIndex) { ResetCrewListIndex(character); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add character to the list without actually adding it to the crew
|
||||
/// </summary>
|
||||
public void AddCharacterToCrewList(Character character)
|
||||
public GUIComponent AddCharacterToCrewList(Character character)
|
||||
{
|
||||
if (character == null) { return; }
|
||||
if (character == null) { return null; }
|
||||
|
||||
var background = new GUIFrame(
|
||||
new RectTransform(crewListEntrySize, parent: crewList.Content.RectTransform, anchor: Anchor.TopRight),
|
||||
@@ -510,6 +511,8 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return background;
|
||||
}
|
||||
|
||||
private void SetCharacterComponentTooltip(GUIComponent characterComponent)
|
||||
@@ -549,13 +552,13 @@ namespace Barotrauma
|
||||
if (characterInfos.Contains(revivedCharacter.Info)) { AddCharacter(revivedCharacter); }
|
||||
}
|
||||
|
||||
public void KillCharacter(Character killedCharacter)
|
||||
public void KillCharacter(Character killedCharacter, bool resetCrewListIndex = true)
|
||||
{
|
||||
if (crewList.Content.GetChildByUserData(killedCharacter) is GUIComponent characterComponent)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(KillCharacterAnim(characterComponent));
|
||||
}
|
||||
RemoveCharacter(killedCharacter);
|
||||
RemoveCharacter(killedCharacter, resetCrewListIndex: resetCrewListIndex);
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> KillCharacterAnim(GUIComponent component)
|
||||
@@ -601,9 +604,53 @@ namespace Barotrauma
|
||||
{
|
||||
if (crewList != this.crewList) { return; }
|
||||
if (!(draggedElementData is Character)) { return; }
|
||||
if (crewList.HasDraggedElementIndexChanged) { return; }
|
||||
if (!IsSinglePlayer) { return; }
|
||||
CharacterClicked(crewList.DraggedElement, draggedElementData);
|
||||
if (crewList.HasDraggedElementIndexChanged)
|
||||
{
|
||||
UpdateCrewListIndices();
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterClicked(crewList.DraggedElement, draggedElementData);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetCrewListIndex(Character c)
|
||||
{
|
||||
if (c?.Info == null) { return; }
|
||||
c.Info.CrewListIndex = -1;
|
||||
UpdateCrewListIndices();
|
||||
}
|
||||
|
||||
private void UpdateCrewListIndices()
|
||||
{
|
||||
if (crewList == null) { return; }
|
||||
for (int i = 0; i < crewList.Content.CountChildren; i++)
|
||||
{
|
||||
var characterComponent = crewList.Content.GetChild(i);
|
||||
if (!(characterComponent?.UserData is Character c)) { continue; }
|
||||
if (c.Info == null) { continue; }
|
||||
c.Info.CrewListIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
private void SortCrewList()
|
||||
{
|
||||
if (crewList == null) { return; }
|
||||
crewList.Content.RectTransform.SortChildren((x, y) =>
|
||||
{
|
||||
var infoX = (x.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
var infoY = (y.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
if (infoX.HasValue)
|
||||
{
|
||||
return infoY.HasValue ? infoX.Value.CompareTo(infoY.Value) : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return infoY.HasValue ? 1 : 0;
|
||||
}
|
||||
});
|
||||
UpdateCrewListIndices();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1077,7 +1124,13 @@ namespace Barotrauma
|
||||
private string CreateOrderTooltip(Order orderPrefab, string option, Entity targetEntity)
|
||||
{
|
||||
if (orderPrefab == null) { return ""; }
|
||||
if (!string.IsNullOrEmpty(option))
|
||||
if (orderPrefab.DisplayGiverInTooltip && orderPrefab.OrderGiver != null)
|
||||
{
|
||||
return TextManager.GetWithVariables("crewlistordericontooltip",
|
||||
new string[2] { "[ordername]", "[orderoption]" },
|
||||
new string[2] { orderPrefab.Name, orderPrefab.OrderGiver.DisplayName });
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(option))
|
||||
{
|
||||
return TextManager.GetWithVariables("crewlistordericontooltip",
|
||||
new string[2] { "[ordername]", "[orderoption]" },
|
||||
@@ -1210,6 +1263,10 @@ namespace Barotrauma
|
||||
DisableCommandUI();
|
||||
Character.Controlled = character;
|
||||
HintManager.OnChangeCharacter();
|
||||
if (GameSession.TabMenuInstance != null && TabMenu.SelectedTab == TabMenu.InfoFrameTab.Talents)
|
||||
{
|
||||
GameSession.TabMenuInstance.SelectInfoFrameTab(TabMenu.SelectedTab);
|
||||
}
|
||||
}
|
||||
|
||||
private int TryAdjustIndex(int amount)
|
||||
@@ -1566,10 +1623,28 @@ namespace Barotrauma
|
||||
{
|
||||
crewList.Select(character, force: true);
|
||||
}
|
||||
// Icon colors might change based on the target so we check if they need to be updated
|
||||
if (GetCurrentOrderIconList(characterComponent) is GUIListBox currentOrderIconList)
|
||||
{
|
||||
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
||||
{
|
||||
if (!(orderIcon.UserData is OrderInfo orderInfo)) { continue; }
|
||||
if (!(orderInfo.Order is Order order)) { continue; }
|
||||
if (order.ColoredWhenControllingGiver && order.OrderGiver != Character.Controlled)
|
||||
{
|
||||
orderIcon.Color = AIObjective.ObjectiveIconColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
orderIcon.Color = order.Color;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Only update the order highlights and objective icons here in singleplayer
|
||||
// The server will let the clients know when they need to update in multiplayer
|
||||
if (GameMain.IsSingleplayer && character.IsBot && character.AIController is HumanAIController controller &&
|
||||
controller.ObjectiveManager is AIObjectiveManager objectiveManager)
|
||||
{
|
||||
// In multiplayer, these are set through character networking (the server lets the clients now when these are updated)
|
||||
if (objectiveManager.CurrentObjective is AIObjective currentObjective)
|
||||
{
|
||||
if (objectiveManager.IsOrder(currentObjective))
|
||||
@@ -1638,8 +1713,8 @@ namespace Barotrauma
|
||||
bool foundMatch = false;
|
||||
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
||||
{
|
||||
var glowComponent = orderIcon.GetChildByUserData("glow");
|
||||
if (glowComponent == null) { continue; }
|
||||
if (!(orderIcon.GetChildByUserData("glow") is GUIComponent glowComponent)) { continue; }
|
||||
glowComponent.Color = orderIcon.Color;
|
||||
if (foundMatch)
|
||||
{
|
||||
glowComponent.Visible = false;
|
||||
@@ -1684,11 +1759,11 @@ namespace Barotrauma
|
||||
objectiveIconFrame.ClearChildren();
|
||||
if (sprite != null)
|
||||
{
|
||||
var objectiveIcon = CreateNodeIcon(Vector2.One, objectiveIconFrame.RectTransform, sprite, Color.LightGray, tooltip: tooltip);
|
||||
var objectiveIcon = CreateNodeIcon(Vector2.One, objectiveIconFrame.RectTransform, sprite, AIObjective.ObjectiveIconColor, tooltip: tooltip);
|
||||
new GUIFrame(new RectTransform(new Vector2(1.5f), objectiveIcon.RectTransform, anchor: Anchor.Center), style: "OuterGlowCircular")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = Color.LightGray
|
||||
Color = AIObjective.ObjectiveIconColor
|
||||
};
|
||||
objectiveIconFrame.Visible = true;
|
||||
}
|
||||
@@ -1909,7 +1984,7 @@ namespace Barotrauma
|
||||
ScaleCommandUI();
|
||||
|
||||
commandFrame = new GUIFrame(
|
||||
new RectTransform(Vector2.One, GUICanvas.Instance, anchor: Anchor.Center),
|
||||
new RectTransform(Vector2.One, GUI.Canvas, anchor: Anchor.Center),
|
||||
style: null,
|
||||
color: Color.Transparent);
|
||||
background = new GUIImage(
|
||||
@@ -3530,12 +3605,14 @@ namespace Barotrauma
|
||||
public void Save(XElement parentElement)
|
||||
{
|
||||
XElement element = new XElement("crew");
|
||||
foreach (CharacterInfo ci in characterInfos)
|
||||
for (int i = 0; i < characterInfos.Count; i++)
|
||||
{
|
||||
var ci = characterInfos[i];
|
||||
var infoElement = ci.Save(element);
|
||||
if (ci.InventoryData != null) { infoElement.Add(ci.InventoryData); }
|
||||
if (ci.HealthData != null) { infoElement.Add(ci.HealthData); }
|
||||
if (ci.OrderData != null) { infoElement.Add(ci.OrderData); }
|
||||
infoElement.Add(new XAttribute("crewlistindex", ci.CrewListIndex));
|
||||
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
||||
}
|
||||
SaveActiveOrders(element);
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUICanvas.Instance),
|
||||
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUI.Canvas),
|
||||
isHorizontal: true, childAnchor: Anchor.CenterRight)
|
||||
{
|
||||
CanBeFocused = false
|
||||
@@ -108,7 +108,7 @@ namespace Barotrauma
|
||||
buttonCenter = buttonHeight / 2,
|
||||
screenMiddle = GameMain.GraphicsWidth / 2;
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle - buttonWidth / 2, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle - buttonWidth / 2, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, buttonWidth, buttonHeight), GUI.Canvas),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
{
|
||||
Pulse = true,
|
||||
@@ -145,7 +145,7 @@ namespace Barotrauma
|
||||
int readyButtonHeight = buttonHeight;
|
||||
int readyButtonWidth = (int) (GUI.Scale * 50);
|
||||
|
||||
ReadyCheckButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle + (buttonWidth / 2) + GUI.IntScale(16), HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, readyButtonWidth, readyButtonHeight), GUICanvas.Instance),
|
||||
ReadyCheckButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle + (buttonWidth / 2) + GUI.IntScale(16), HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, readyButtonWidth, readyButtonHeight), GUI.Canvas),
|
||||
style: "RepairBuyButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("ReadyCheck.Tooltip"),
|
||||
|
||||
@@ -108,6 +108,9 @@ namespace Barotrauma
|
||||
case "pets":
|
||||
petsElement = subElement;
|
||||
break;
|
||||
case "stats":
|
||||
LoadStats(subElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +170,7 @@ namespace Barotrauma
|
||||
int buttonHeight = (int)(GUI.Scale * 40);
|
||||
int buttonWidth = GUI.IntScale(450);
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUI.Canvas),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
{
|
||||
Pulse = true,
|
||||
@@ -412,6 +415,10 @@ namespace Barotrauma
|
||||
break;
|
||||
case TransitionType.ProgressToNextLocation:
|
||||
Map.MoveToNextLocation();
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
case TransitionType.ProgressToNextEmptyLocation:
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -728,6 +735,7 @@ namespace Barotrauma
|
||||
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
|
||||
new XAttribute("cheatsenabled", CheatsEnabled));
|
||||
modeElement.Add(Settings.Save());
|
||||
modeElement.Add(SaveStats());
|
||||
|
||||
//save and remove all items that are in someone's inventory so they don't get included in the sub file as well
|
||||
foreach (Character c in Character.CharacterList)
|
||||
|
||||
@@ -205,6 +205,11 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign?.CampaignUI?.MedicalClinic is { } ui)
|
||||
{
|
||||
ui.ClosePopup();
|
||||
}
|
||||
|
||||
healAllRequests.Add(new RequestAction<HealRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
@@ -600,6 +600,10 @@ namespace Barotrauma
|
||||
OnClicked = (bt, userdata) => { SelectTab((Tab)userdata); return true; }
|
||||
};
|
||||
tabButtons[(int)tab].Text = ToolBox.LimitString(buttonText, tabButtons[(int)tab].Font, (int)(0.75f * tabWidth * tabButtonHolder.Rect.Width));
|
||||
if (tabButtons[(int)tab].Text != buttonText)
|
||||
{
|
||||
tabButtons[(int)tab].ToolTip = buttonText;
|
||||
}
|
||||
}
|
||||
|
||||
/// Graphics tab --------------------------------------------------------------
|
||||
|
||||
@@ -796,7 +796,7 @@ namespace Barotrauma
|
||||
if (quickUseAction != QuickUseAction.Drop)
|
||||
{
|
||||
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
|
||||
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", item?.Name);
|
||||
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", character.HeldItems.FirstOrDefault()?.Name ?? item?.Name);
|
||||
if (PlayerInput.PrimaryMouseButtonDown()) { slot.EquipButtonState = GUIComponent.ComponentState.Pressed; }
|
||||
if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
@@ -970,7 +970,9 @@ namespace Barotrauma
|
||||
{
|
||||
return QuickUseAction.TakeFromCharacter;
|
||||
}
|
||||
else if (character.HeldItems.Any(i => i.OwnInventory != null && i.OwnInventory.CanBePut(item)) && allowInventorySwap)
|
||||
else if (character.HeldItems.Any(i =>
|
||||
i.OwnInventory != null &&
|
||||
(i.OwnInventory.CanBePut(item) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))))
|
||||
{
|
||||
return QuickUseAction.PutToEquippedItem;
|
||||
}
|
||||
@@ -1136,7 +1138,8 @@ namespace Barotrauma
|
||||
foreach (Item heldItem in character.HeldItems)
|
||||
{
|
||||
if (heldItem.OwnInventory != null &&
|
||||
heldItem.OwnInventory.TryPutItem(item, Character.Controlled))
|
||||
heldItem.OwnInventory.TryPutItem(item, Character.Controlled) ||
|
||||
(heldItem.OwnInventory.Capacity == 1 && heldItem.OwnInventory.TryPutItem(item, 0, allowSwapping: true, allowCombine: false, user: Character.Controlled)))
|
||||
{
|
||||
success = true;
|
||||
for (int j = 0; j < capacity; j++)
|
||||
|
||||
@@ -256,6 +256,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
targetHull.IncreaseSectionColorOrStrength(targetSections[i], color, sizeAdjustedSprayStrength * deltaTime, true, false);
|
||||
}
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
GameMain.GameSession.TimeSpentCleaning += deltaTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,6 +267,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
targetHull.CleanSection(targetSections[i], -sizeAdjustedSprayStrength * deltaTime, true);
|
||||
}
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
GameMain.GameSession.TimeSpentPainting += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 particleStartPos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public GUIFrame GuiFrame { get; protected set; }
|
||||
public GUIFrame GuiFrame { get; set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool AllowUIOverlap
|
||||
@@ -554,7 +554,7 @@ namespace Barotrauma.Items.Components
|
||||
color = GuiFrameSource.GetAttributeColor("color", Color.White);
|
||||
}
|
||||
string style = GuiFrameSource.Attribute("style") == null ? null : GuiFrameSource.GetAttributeString("style", "");
|
||||
GuiFrame = new GUIFrame(RectTransform.Load(GuiFrameSource, GUI.Canvas.ItemComponentHolder, Anchor.Center), style, color);
|
||||
GuiFrame = new GUIFrame(RectTransform.Load(GuiFrameSource, GUI.Canvas, Anchor.Center), style, color);
|
||||
DefaultLayout = GUILayoutSettings.Load(GuiFrameSource);
|
||||
if (GuiFrame != null)
|
||||
{
|
||||
|
||||
@@ -76,6 +76,9 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false, description: "If true, the contained state indicator calculates how full the item is based on the total amount of items that can be stacked inside it, as opposed to how many of the inventory slots are occupied.")]
|
||||
public bool ShowTotalStackCapacityInContainedStateIndicator { get; set; }
|
||||
|
||||
[Serialize(false, false, description: "Should the inventory of this item be kept open when the item is equipped by a character.")]
|
||||
public bool KeepOpenWhenEquipped { get; set; }
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Barotrauma.Items.Components
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, inputLabelArea.RectTransform), TextManager.Get("uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, inputLabelArea.RectTransform), TextManager.Get("deconstructor.input", fallBackTag: "uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
inputLabel.RectTransform.Resize(new Point((int) inputLabel.Font.MeasureString(inputLabel.Text).X, inputLabel.RectTransform.Rect.Height));
|
||||
new GUIFrame(new RectTransform(Vector2.One, inputLabelArea.RectTransform), style: "HorizontalLine");
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Barotrauma.Items.Components
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.03f
|
||||
};
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, separatorArea.RectTransform), TextManager.Get("uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, separatorArea.RectTransform), TextManager.Get("fabricator.input", fallBackTag: "uilabel.input"), font: GUI.SubHeadingFont) { Padding = Vector4.Zero };
|
||||
inputLabel.RectTransform.Resize(new Point((int) inputLabel.Font.MeasureString(inputLabel.Text).X, inputLabel.RectTransform.Rect.Height));
|
||||
new GUIFrame(new RectTransform(Vector2.One, separatorArea.RectTransform), style: "HorizontalLine");
|
||||
|
||||
|
||||
@@ -507,7 +507,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Vector2 origin = weaponSprite.Origin;
|
||||
float scale = parentWidth / Math.Max(weaponSprite.size.X, weaponSprite.size.Y);
|
||||
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? GUI.Style.Red : GUI.Style.Green;
|
||||
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? Color.DimGray : GUI.Style.Green;
|
||||
weaponSprite.Draw(batch, center, color, origin, rotation, scale, it.SpriteEffects);
|
||||
}
|
||||
});
|
||||
@@ -1335,7 +1335,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
RectangleF entityRect = ScaleRectToUI(structure, parent, border);
|
||||
Vector2 spriteScale = new Vector2(entityRect.Size.X / sprite.size.X, entityRect.Size.Y / sprite.size.Y);
|
||||
sprite.Draw(spriteBatch, new Vector2(entityRect.Location.X + inflate, entityRect.Location.Y + inflate), structure.SpriteColor, Vector2.Zero, 0f, spriteScale, structure.SpriteEffects);
|
||||
sprite.Draw(spriteBatch, new Vector2(entityRect.Location.X + inflate, entityRect.Location.Y + inflate), structure.SpriteColor, Vector2.Zero, 0f, spriteScale, sprite.effects ^ structure.SpriteEffects);
|
||||
}
|
||||
|
||||
private static RectangleF ScaleRectToUI(MapEntity entity, RectangleF parentRect, RectangleF worldBorders)
|
||||
@@ -1718,5 +1718,20 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
return new MiniMapHullData(scaledPolygon, worldRect, parentRect.Size, snappedRectangles, hullRefs.ToImmutableArray());
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
if (searchAutoComplete != null)
|
||||
{
|
||||
searchAutoComplete.RectTransform.Parent = null;
|
||||
searchAutoComplete = null;
|
||||
}
|
||||
if (hullInfoFrame != null)
|
||||
{
|
||||
hullInfoFrame.RectTransform.Parent = null;
|
||||
hullInfoFrame = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (selectionUI == null)
|
||||
{
|
||||
selectionUI = new SubmarineSelection(true, null, GUICanvas.Instance.ItemComponentHolder);
|
||||
selectionUI = new SubmarineSelection(true, null, GUI.Canvas);
|
||||
}
|
||||
|
||||
GuiFrame = selectionUI.GuiFrame;
|
||||
@@ -35,5 +35,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
selectionUI?.Update();
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
if (selectionUI != null)
|
||||
{
|
||||
selectionUI.GuiFrame.RectTransform.Parent = null;
|
||||
selectionUI = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,6 +348,27 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 GetTransducerPos()
|
||||
{
|
||||
if (!UseTransducers || connectedTransducers.Count == 0)
|
||||
{
|
||||
//use the position of the sub if the item is static (no body) and inside a sub
|
||||
return item.Submarine != null && item.body == null ? item.Submarine.WorldPosition : item.WorldPosition;
|
||||
}
|
||||
|
||||
Vector2 transducerPosSum = Vector2.Zero;
|
||||
foreach (ConnectedTransducer transducer in connectedTransducers)
|
||||
{
|
||||
if (transducer.Transducer.Item.Submarine != null && !CenterOnTransducers)
|
||||
{
|
||||
return transducer.Transducer.Item.Submarine.WorldPosition;
|
||||
}
|
||||
transducerPosSum += transducer.Transducer.Item.WorldPosition;
|
||||
}
|
||||
return transducerPosSum / connectedTransducers.Count;
|
||||
}
|
||||
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
|
||||
@@ -10,6 +10,12 @@ namespace Barotrauma.Items.Components
|
||||
private GUIProgressBar chargeIndicator;
|
||||
private GUIScrollBar rechargeSpeedSlider;
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float RechargeWarningIndicatorLow { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float RechargeWarningIndicatorHigh { get; set; }
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
//use the extents of the item as the draw size
|
||||
@@ -28,19 +34,38 @@ namespace Barotrauma.Items.Components
|
||||
var upperArea = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), paddedFrame.RectTransform, Anchor.TopCenter), style: null);
|
||||
var lowerArea = new GUIFrame(new RectTransform(new Vector2(1, 0.6f), paddedFrame.RectTransform, Anchor.BottomCenter), style: null);
|
||||
|
||||
|
||||
string rechargeStr = TextManager.Get("PowerContainerRechargeRate");
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), upperArea.RectTransform, Anchor.TopCenter),
|
||||
"RechargeRate", textColor: GUI.Style.TextColor, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
|
||||
var rechargeRateContainer = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), upperArea.RectTransform), style: null);
|
||||
var rechargeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.0f), rechargeRateContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get("rechargerate"), textColor: GUI.Style.TextColor, font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
string kW = TextManager.Get("kilowatt");
|
||||
var rechargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), rechargeRateContainer.RectTransform, Anchor.CenterRight),
|
||||
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = () =>
|
||||
{
|
||||
return rechargeStr.Replace("[rate]", ((int)((rechargeSpeed / maxRechargeSpeed) * 100.0f)).ToString());
|
||||
}
|
||||
TextGetter = () => $"{(int)MathF.Round(currPowerConsumption)} {kW} ({(int)MathF.Round(RechargeRatio * 100)} %)"
|
||||
};
|
||||
if (rechargeText.TextSize.X > rechargeText.Rect.Width) { rechargeText.Font = GUI.SmallFont; }
|
||||
|
||||
rechargeSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 0.4f), upperArea.RectTransform, Anchor.BottomCenter),
|
||||
barSize: 0.15f, style: "DeviceSlider")
|
||||
var rechargeSliderContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.4f), upperArea.RectTransform, Anchor.BottomCenter));
|
||||
|
||||
if (RechargeWarningIndicatorLow > 0.0f || RechargeWarningIndicatorHigh > 0.0f)
|
||||
{
|
||||
var rechargeSliderFill = new GUICustomComponent(new RectTransform(new Vector2(0.95f, 0.9f), rechargeSliderContainer.RectTransform, Anchor.Center), (SpriteBatch sb, GUICustomComponent c) =>
|
||||
{
|
||||
if (RechargeWarningIndicatorLow > 0.0f)
|
||||
{
|
||||
float warningLow = c.Rect.Width * RechargeWarningIndicatorLow;
|
||||
GUI.DrawRectangle(sb, new Vector2(c.Rect.X + warningLow, c.Rect.Y), new Vector2(c.Rect.Width - warningLow, c.Rect.Height), GUI.Style.Orange, isFilled: true);
|
||||
}
|
||||
if (RechargeWarningIndicatorHigh > 0.0f)
|
||||
{
|
||||
float warningHigh = c.Rect.Width * RechargeWarningIndicatorHigh;
|
||||
GUI.DrawRectangle(sb, new Vector2(c.Rect.X + warningHigh, c.Rect.Y), new Vector2(c.Rect.Width - warningHigh, c.Rect.Height), GUI.Style.Red, isFilled: true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
rechargeSpeedSlider = new GUIScrollBar(new RectTransform(Vector2.One, rechargeSliderContainer.RectTransform, Anchor.Center),
|
||||
barSize: 0.15f, style: "DeviceSliderSeeThrough")
|
||||
{
|
||||
Step = 0.1f,
|
||||
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||
@@ -61,17 +86,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
// lower area --------------------------
|
||||
|
||||
var textArea = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), lowerArea.RectTransform), style: null);
|
||||
var chargeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.0f), textArea.RectTransform, Anchor.CenterLeft),
|
||||
var chargeTextContainer = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), lowerArea.RectTransform), style: null);
|
||||
var chargeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.0f), chargeTextContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get("charge"), textColor: GUI.Style.TextColor, font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
ToolTip = TextManager.Get("PowerTransferTipPower")
|
||||
};
|
||||
string kWmin = TextManager.Get("kilowattminute");
|
||||
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), textArea.RectTransform, Anchor.CenterRight),
|
||||
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), chargeTextContainer.RectTransform, Anchor.CenterRight),
|
||||
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = () => $"{(int)Math.Round(charge)}/{(int)capacity} {kWmin} ({(int)Math.Round(MathUtils.Percentage(charge, capacity))} %)"
|
||||
TextGetter = () => $"{(int)MathF.Round(charge)}/{(int)capacity} {kWmin} ({(int)MathF.Round(MathUtils.Percentage(charge, capacity))} %)"
|
||||
};
|
||||
if (chargeText.TextSize.X > chargeText.Rect.Width) { chargeText.Font = GUI.SmallFont; }
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -19,5 +20,10 @@ namespace Barotrauma.Items.Components
|
||||
ShapeExtensions.DrawLine(spriteBatch, pos + Vector2.UnitX * range, pos - Vector2.UnitX * range, Color.Cyan * 0.5f, 2);
|
||||
ShapeExtensions.DrawCircle(spriteBatch, pos, range, 32, Color.Cyan * 0.5f, 3);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Channel = msg.ReadRangedInteger(MinChannel, MaxChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1584,6 +1584,10 @@ namespace Barotrauma
|
||||
{
|
||||
containedState = item.Condition / item.MaxCondition;
|
||||
}
|
||||
else if (itemContainer.ShowTotalStackCapacityInContainedStateIndicator)
|
||||
{
|
||||
containedState = itemContainer.Inventory.AllItems.Count() / (float)(itemContainer.GetMaxStackSize(0) * itemContainer.Capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var containedItem = itemContainer.Inventory.slots[Math.Max(itemContainer.ContainedStateIndicatorSlot, 0)].FirstOrDefault();
|
||||
|
||||
@@ -315,7 +315,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveClaim(itemId);
|
||||
RemoveClaim(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -128,13 +128,13 @@ namespace Barotrauma
|
||||
{
|
||||
//no flow particles between linked hulls (= rooms consisting of multiple hulls)
|
||||
if (hull1.linkedTo.Contains(hull2)) { return; }
|
||||
foreach (Hull h in hull1.linkedTo)
|
||||
foreach (var linkedEntity in hull1.linkedTo)
|
||||
{
|
||||
if (h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
if (linkedEntity is Hull h && h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
}
|
||||
foreach (Hull h in hull2.linkedTo)
|
||||
foreach (var linkedEntity in hull2.linkedTo)
|
||||
{
|
||||
if (h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
if (linkedEntity is Hull h && h.linkedTo.Contains(hull1) && h.linkedTo.Contains(hull2)) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace Barotrauma
|
||||
float emitInterval = 1.0f / particlesPerSec;
|
||||
while (particleTimer > emitInterval)
|
||||
{
|
||||
pos.X = Rand.Range(rect.X, rect.X + rect.Width);
|
||||
pos.X = Rand.Range(rect.X, rect.X + rect.Width + 1);
|
||||
Vector2 velocity = new Vector2(
|
||||
lerpedFlowForce.X * Rand.Range(0.5f, 0.7f),
|
||||
MathHelper.Clamp(lerpedFlowForce.Y, -500.0f, 1000.0f) * Rand.Range(0.5f, 0.7f));
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Barotrauma
|
||||
var prefab = ToolBox.SelectWeightedRandom(availablePrefabs, availablePrefabs.Select(p => p.GetCommonness(level.GenerationParams)).ToList(), Rand.RandSync.ClientOnly);
|
||||
if (prefab == null) { break; }
|
||||
|
||||
int amount = Rand.Range(prefab.SwarmMin, prefab.SwarmMax, Rand.RandSync.ClientOnly);
|
||||
int amount = Rand.Range(prefab.SwarmMin, prefab.SwarmMax + 1, Rand.RandSync.ClientOnly);
|
||||
List<BackgroundCreature> swarmMembers = new List<BackgroundCreature>();
|
||||
for (int n = 0; n < amount; n++)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Lights;
|
||||
|
||||
@@ -36,9 +37,6 @@ namespace Barotrauma
|
||||
|
||||
private static List<MapEntity> highlightedList = new List<MapEntity>();
|
||||
|
||||
// Test feature. Not yet saved.
|
||||
public static Dictionary<MapEntity, HashSet<MapEntity>> SelectionGroups { get; private set; } = new Dictionary<MapEntity, HashSet<MapEntity>>();
|
||||
|
||||
private static float highlightTimer;
|
||||
|
||||
private static GUIListBox highlightedListBox;
|
||||
@@ -197,7 +195,7 @@ namespace Barotrauma
|
||||
{
|
||||
Paste(cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.G))
|
||||
/*else if (PlayerInput.KeyHit(Keys.G))
|
||||
{
|
||||
if (SelectedList.Any())
|
||||
{
|
||||
@@ -217,7 +215,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,14 +358,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (highLightedEntity != null)
|
||||
{
|
||||
if (SelectionGroups.TryGetValue(highLightedEntity, out HashSet<MapEntity> group))
|
||||
if (SubEditorScreen.IsLayerLinked(highLightedEntity)/*SelectionGroups.TryGetValue(highLightedEntity, out HashSet<MapEntity> group)*/)
|
||||
{
|
||||
foreach (MapEntity entity in group.Where(e => !newSelection.Contains(e)))
|
||||
ImmutableHashSet<MapEntity> entitiesInSameLayer = SubEditorScreen.GetEntitiesInSameLayer(highLightedEntity);
|
||||
foreach (MapEntity entity in entitiesInSameLayer.Where(e => !newSelection.Contains(e)))
|
||||
{
|
||||
newSelection.Add(entity);
|
||||
}
|
||||
|
||||
foreach (MapEntity entity in group)
|
||||
foreach (MapEntity entity in entitiesInSameLayer)
|
||||
{
|
||||
entity.IsIncludedInSelection = true;
|
||||
}
|
||||
@@ -1197,14 +1196,24 @@ namespace Barotrauma
|
||||
|
||||
Rectangle selectionRect = Submarine.AbsRect(pos, size);
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
{
|
||||
if (!e.SelectableInEditor) continue;
|
||||
if (!entity.SelectableInEditor) { continue; }
|
||||
|
||||
if (Submarine.RectsOverlap(selectionRect, e.rect))
|
||||
if (Submarine.RectsOverlap(selectionRect, entity.rect))
|
||||
{
|
||||
foundEntities.Add(e);
|
||||
e.IsIncludedInSelection = true;
|
||||
foundEntities.Add(entity);
|
||||
entity.IsIncludedInSelection = true;
|
||||
|
||||
if (SubEditorScreen.IsLayerLinked(entity))
|
||||
{
|
||||
ImmutableHashSet<MapEntity> entitiesInSameLayer = SubEditorScreen.GetEntitiesInSameLayer(entity);
|
||||
foreach (MapEntity layerEntity in entitiesInSameLayer.Where(e => !foundEntities.Contains(e)))
|
||||
{
|
||||
foundEntities.Add(layerEntity);
|
||||
layerEntity.IsIncludedInSelection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -651,7 +651,11 @@ namespace Barotrauma
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
previewFrame = null;
|
||||
if (previewFrame != null)
|
||||
{
|
||||
previewFrame.RectTransform.Parent = null;
|
||||
previewFrame = null;
|
||||
}
|
||||
spriteRecorder?.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,13 @@ namespace Barotrauma.Networking
|
||||
senderName = senderCharacter.Name;
|
||||
}
|
||||
}
|
||||
|
||||
Color? textColor = null;
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
textColor = msg.ReadColorR8G8B8A8();
|
||||
}
|
||||
|
||||
msg.ReadPadBits();
|
||||
|
||||
switch (type)
|
||||
@@ -135,14 +142,18 @@ namespace Barotrauma.Networking
|
||||
//only show the message box if the text differs from the text in the currently visible box
|
||||
if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt)
|
||||
{
|
||||
new GUIMessageBox("", txt);
|
||||
GUIMessageBox messageBox = new GUIMessageBox("", txt);
|
||||
if (textColor != null) { messageBox.Text.TextColor = textColor.Value; }
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.ServerMessageBoxInGame:
|
||||
new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
|
||||
{
|
||||
GUIMessageBox messageBox = new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
|
||||
if (textColor != null) { messageBox.Text.TextColor = textColor.Value; }
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.Console:
|
||||
DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]);
|
||||
DebugConsole.NewMessage(txt, textColor == null ? MessageColor[(int)ChatMessageType.Console] : textColor.Value);
|
||||
break;
|
||||
case ChatMessageType.ServerLog:
|
||||
if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType))
|
||||
@@ -152,7 +163,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
|
||||
break;
|
||||
default:
|
||||
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType);
|
||||
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType, textColor: textColor);
|
||||
break;
|
||||
}
|
||||
LastID = id;
|
||||
|
||||
@@ -857,7 +857,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
break;
|
||||
case ServerPacketHeader.STARTGAMEFINALIZE:
|
||||
DebugConsole.Log("Received STARTGAMEFINALIZE packet.");
|
||||
DebugConsole.NewMessage("Received STARTGAMEFINALIZE packet. Round init status: " + roundInitStatus);
|
||||
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
|
||||
{
|
||||
//waiting for a save file
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using Barotrauma.Tutorials;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Globalization;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -64,6 +61,7 @@ namespace Barotrauma
|
||||
maxMissionCount = MathHelper.Clamp(maxMissionCount,
|
||||
CampaignSettings.MinMissionCountLimit,
|
||||
CampaignSettings.MaxMissionCountLimit);
|
||||
|
||||
maxMissionCountText.Text = maxMissionCount.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
maxMissionCountButtons[1]
|
||||
|
||||
@@ -151,6 +151,7 @@ namespace Barotrauma
|
||||
if (Campaign.Money >= CampaignMode.HullRepairCost)
|
||||
{
|
||||
Campaign.Money -= CampaignMode.HullRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(CampaignMode.HullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
Campaign.PurchasedHullRepairs = true;
|
||||
}
|
||||
}
|
||||
@@ -196,6 +197,7 @@ namespace Barotrauma
|
||||
if (Campaign.Money >= CampaignMode.ItemRepairCost)
|
||||
{
|
||||
Campaign.Money -= CampaignMode.ItemRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(CampaignMode.ItemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
Campaign.PurchasedItemRepairs = true;
|
||||
}
|
||||
}
|
||||
@@ -248,6 +250,7 @@ namespace Barotrauma
|
||||
if (Campaign.Money >= CampaignMode.ShuttleReplaceCost)
|
||||
{
|
||||
Campaign.Money -= CampaignMode.ShuttleReplaceCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(CampaignMode.ShuttleReplaceCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
|
||||
Campaign.PurchasedLostShuttles = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Barotrauma
|
||||
|
||||
private void CreateGUI()
|
||||
{
|
||||
GuiFrame = new GUIFrame(new RectTransform(new Vector2(0.2f, 0.4f), GUICanvas.Instance) { MinSize = new Point(300, 400) });
|
||||
GuiFrame = new GUIFrame(new RectTransform(new Vector2(0.2f, 0.4f), GUI.Canvas) { MinSize = new Point(300, 400) });
|
||||
GUILayoutGroup layoutGroup = new GUILayoutGroup(RectTransform(0.9f, 0.9f, GuiFrame, Anchor.Center)) { Stretch = true };
|
||||
|
||||
// === BUTTONS === //
|
||||
|
||||
@@ -501,8 +501,6 @@ namespace Barotrauma
|
||||
|
||||
ResetButtonStates(null);
|
||||
|
||||
GameAnalyticsManager.SetCustomDimension01("");
|
||||
|
||||
if (GameMain.SteamWorkshopScreen != null)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(GameMain.SteamWorkshopScreen.RefreshDownloadState());
|
||||
@@ -1019,7 +1017,10 @@ namespace Barotrauma
|
||||
|
||||
if (backgroundSprite == null)
|
||||
{
|
||||
backgroundSprite = (LocationType.List.Where(l => l.UseInMainMenu).GetRandom())?.GetPortrait(0);
|
||||
#if UNSTABLE
|
||||
backgroundSprite = new Sprite("Content/UnstableBackground.png", sourceRectangle: null);
|
||||
#endif
|
||||
backgroundSprite ??= LocationType.List.Where(l => l.UseInMainMenu).GetRandom()?.GetPortrait(0);
|
||||
}
|
||||
|
||||
if (backgroundSprite != null)
|
||||
@@ -1159,7 +1160,7 @@ namespace Barotrauma
|
||||
//GameMain.LobbyScreen.Select();
|
||||
}
|
||||
|
||||
#region UI Methods
|
||||
#region UI Methods
|
||||
private void CreateCampaignSetupUI()
|
||||
{
|
||||
menuTabs[(int)Tab.NewGame].ClearChildren();
|
||||
@@ -1432,7 +1433,7 @@ namespace Barotrauma
|
||||
playstyleDescription.TextAlignment = playstyleDescription.WrappedText.Contains('\n') ?
|
||||
Alignment.CenterLeft : Alignment.Center;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
private void FetchRemoteContent()
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (frame == null)
|
||||
{
|
||||
frame = new GUIFrame(new RectTransform(GUICanvas.Instance.RelativeSize, GUICanvas.Instance), style: null)
|
||||
frame = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml.Linq;
|
||||
@@ -21,6 +22,38 @@ namespace Barotrauma
|
||||
{
|
||||
class SubEditorScreen : EditorScreen
|
||||
{
|
||||
private enum LayerVisibility
|
||||
{
|
||||
Visible,
|
||||
Invisible
|
||||
}
|
||||
|
||||
private enum LayerLinkage
|
||||
{
|
||||
Unlinked,
|
||||
Linked
|
||||
}
|
||||
|
||||
private readonly struct LayerData
|
||||
{
|
||||
public readonly LayerVisibility Visible;
|
||||
public readonly LayerLinkage Linkage;
|
||||
|
||||
public static readonly LayerData Default = new LayerData(LayerVisibility.Visible, LayerLinkage.Unlinked);
|
||||
|
||||
public LayerData(LayerVisibility visible, LayerLinkage linkage)
|
||||
{
|
||||
Visible = visible;
|
||||
Linkage = linkage;
|
||||
}
|
||||
|
||||
public void Deconstruct(out LayerVisibility isvisible, out LayerLinkage islinked)
|
||||
{
|
||||
isvisible = Visible;
|
||||
islinked = Linkage;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] crewExperienceLevels =
|
||||
{
|
||||
"CrewExperienceLow",
|
||||
@@ -94,6 +127,7 @@ namespace Barotrauma
|
||||
private GUIFrame hullVolumeFrame;
|
||||
|
||||
private GUIFrame saveAssemblyFrame;
|
||||
private GUIFrame snapToGridFrame;
|
||||
|
||||
const int PreviouslyUsedCount = 10;
|
||||
private GUIFrame previouslyUsedPanel;
|
||||
@@ -238,7 +272,7 @@ namespace Barotrauma
|
||||
|
||||
public bool WiringMode => mode == Mode.Wiring;
|
||||
|
||||
public static readonly Dictionary<string, bool> Layers = new Dictionary<string, bool>();
|
||||
private static readonly Dictionary<string, LayerData> Layers = new Dictionary<string, LayerData>();
|
||||
|
||||
public SubEditorScreen()
|
||||
{
|
||||
@@ -507,7 +541,7 @@ namespace Barotrauma
|
||||
|
||||
//-----------------------------------------------
|
||||
|
||||
layerPanel = new GUIFrame(new RectTransform(new Vector2(0.175f, 0.4f), GUI.Canvas))
|
||||
layerPanel = new GUIFrame(new RectTransform(new Vector2(0.2f, 0.4f), GUI.Canvas))
|
||||
{
|
||||
Visible = false
|
||||
};
|
||||
@@ -520,6 +554,7 @@ namespace Barotrauma
|
||||
AutoHideScrollBar = false,
|
||||
OnSelected = (component, o) =>
|
||||
{
|
||||
if (GUI.MouseOn is GUITickBox) { return false; } // lol
|
||||
if (!(o is string layer)) { return false; }
|
||||
|
||||
MapEntity.SelectedList.Clear();
|
||||
@@ -847,6 +882,19 @@ namespace Barotrauma
|
||||
};
|
||||
saveAssemblyFrame.RectTransform.MinSize = new Point(saveAssemblyFrame.Rect.Width, (int)(saveAssemblyButton.Rect.Height / saveAssemblyButton.RectTransform.RelativeSize.Y));
|
||||
|
||||
snapToGridFrame = new GUIFrame(new RectTransform(new Vector2(0.08f, 0.5f), TopPanel.RectTransform, Anchor.BottomLeft, Pivot.TopLeft)
|
||||
{ MinSize = new Point((int)(250 * GUI.Scale), (int)(80 * GUI.Scale)), AbsoluteOffset = new Point((int)(10 * GUI.Scale), -saveAssemblyFrame.Rect.Height - entityCountPanel.Rect.Height - (int)(10 * GUI.Scale)) }, "InnerFrame")
|
||||
{
|
||||
Visible = false
|
||||
};
|
||||
var saveStampButton = new GUIButton(new RectTransform(new Vector2(0.9f, 0.8f), snapToGridFrame.RectTransform, Anchor.Center), TextManager.Get("subeditor.snaptogrid", fallBackTag: "spriteeditor.snaptogrid"));
|
||||
saveStampButton.TextBlock.AutoScaleHorizontal = true;
|
||||
saveStampButton.OnClicked += (btn, userdata) =>
|
||||
{
|
||||
SnapToGrid();
|
||||
return true;
|
||||
};
|
||||
snapToGridFrame.RectTransform.MinSize = new Point(snapToGridFrame.Rect.Width, (int)(saveStampButton.Rect.Height / saveStampButton.RectTransform.RelativeSize.Y));
|
||||
|
||||
//Entity menu
|
||||
//------------------------------------------------
|
||||
@@ -941,7 +989,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
paddedTab.Recalculate();
|
||||
|
||||
UpdateLayerPanel();
|
||||
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
@@ -1161,6 +1209,7 @@ namespace Barotrauma
|
||||
{
|
||||
CanBeFocused = false,
|
||||
LoadAsynchronously = true,
|
||||
SpriteEffects = icon.effects,
|
||||
Color = legacy ? iconColor * 0.6f : iconColor
|
||||
};
|
||||
}
|
||||
@@ -1344,8 +1393,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
ImageManager.OnEditorSelected();
|
||||
ReconstructLayers();
|
||||
|
||||
GameAnalyticsManager.SetCustomDimension01("editor");
|
||||
if (!GameMain.Config.EditorDisclaimerShown)
|
||||
{
|
||||
GameMain.Instance.ShowEditorDisclaimer();
|
||||
@@ -1455,7 +1504,6 @@ namespace Barotrauma
|
||||
loadFrame = null;
|
||||
|
||||
MapEntity.DeselectAll();
|
||||
MapEntity.SelectionGroups.Clear();
|
||||
ClearUndoBuffer();
|
||||
|
||||
SetMode(Mode.Default);
|
||||
@@ -2205,7 +2253,7 @@ namespace Barotrauma
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), priceGroup.RectTransform),
|
||||
TextManager.Get("subeditor.price"), textAlignment: Alignment.CenterLeft, wrap: true);
|
||||
|
||||
int basePrice = GameMain.DebugDraw ? 0 : Submarine.MainSub?.CalculateBasePrice() ?? 1000;
|
||||
int basePrice = (GameMain.DebugDraw ? 0 : Submarine.MainSub?.CalculateBasePrice()) ?? 1000;
|
||||
new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), priceGroup.RectTransform), GUINumberInput.NumberType.Int, hidePlusMinusButtons: true)
|
||||
{
|
||||
IntValue = Math.Max(Submarine.MainSub?.Info?.Price ?? basePrice, basePrice),
|
||||
@@ -2682,6 +2730,38 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SnapToGrid()
|
||||
{
|
||||
// First move components
|
||||
foreach (Item item in MapEntity.SelectedList.Where(entity => entity is Item).Cast<Item>())
|
||||
{
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire == null)
|
||||
{
|
||||
// Items snap to centre of nearest grid square
|
||||
Vector2 offset = item.Position;
|
||||
offset = new Vector2((MathF.Floor(offset.X / Submarine.GridSize.X) + .5f) * Submarine.GridSize.X - offset.X, (MathF.Floor(offset.Y / Submarine.GridSize.Y) + .5f) * Submarine.GridSize.Y - offset.Y);
|
||||
item.Move(offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Then move wires, separated as moving components also moves the start and end node of wires
|
||||
foreach (Item item in MapEntity.SelectedList.Where(entity => entity is Item).Cast<Item>())
|
||||
{
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire != null)
|
||||
{
|
||||
for (int i = 0; i < wire.GetNodes().Count; i++)
|
||||
{
|
||||
// Items wire nodes to centre of nearest grid square
|
||||
Vector2 offset = wire.GetNodes()[i] + Submarine.MainSub.HiddenSubPosition;
|
||||
offset = new Vector2((MathF.Floor(offset.X / Submarine.GridSize.X) + .5f) * Submarine.GridSize.X - offset.X, (MathF.Floor(offset.Y / Submarine.GridSize.Y) + .5f) * Submarine.GridSize.Y - offset.Y);
|
||||
wire.MoveNode(i, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateLoadScreen()
|
||||
{
|
||||
CloseItem();
|
||||
@@ -3232,7 +3312,6 @@ namespace Barotrauma
|
||||
}),
|
||||
new ContextMenuOption("editor.layer.openlayermenu", isEnabled: true, onSelected: () =>
|
||||
{
|
||||
if (visibilityButton is null) { return; }
|
||||
previouslyUsedPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
showEntitiesPanel.Visible = false;
|
||||
@@ -3289,7 +3368,7 @@ namespace Barotrauma
|
||||
MoveToLayer(name, content);
|
||||
}
|
||||
|
||||
Layers.Add(name, true);
|
||||
Layers.Add(name, LayerData.Default);
|
||||
UpdateLayerPanel();
|
||||
}
|
||||
|
||||
@@ -3304,7 +3383,7 @@ namespace Barotrauma
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newName))
|
||||
{
|
||||
Layers.TryAdd(newName, true);
|
||||
Layers.TryAdd(newName, LayerData.Default);
|
||||
}
|
||||
UpdateLayerPanel();
|
||||
}
|
||||
@@ -3316,7 +3395,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(entity.Layer))
|
||||
{
|
||||
Layers.TryAdd(entity.Layer, true);
|
||||
Layers.TryAdd(entity.Layer, LayerData.Default);
|
||||
}
|
||||
}
|
||||
UpdateLayerPanel();
|
||||
@@ -4352,8 +4431,13 @@ namespace Barotrauma
|
||||
layerList.Content.ClearChildren();
|
||||
|
||||
layerList.Deselect();
|
||||
GUILayoutGroup buttonHeaders = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.075f), layerList.Content.RectTransform), isHorizontal: true, childAnchor: Anchor.BottomLeft);
|
||||
|
||||
foreach (var (layer, isVisible) in Layers)
|
||||
new GUIButton(new RectTransform(new Vector2(0.25f, 1f), buttonHeaders.RectTransform), TextManager.Get("editor.layer.headervisible"), style: "GUIButtonSmallFreeScale") { CanBeFocused = false, ForceUpperCase = true };
|
||||
new GUIButton(new RectTransform(new Vector2(0.15f, 1f), buttonHeaders.RectTransform), TextManager.Get("editor.layer.headerlink"), style: "GUIButtonSmallFreeScale") { CanBeFocused = false, ForceUpperCase = true };
|
||||
new GUIButton(new RectTransform(new Vector2(0.65f, 1f), buttonHeaders.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale") { CanBeFocused = false, ForceUpperCase = true };
|
||||
|
||||
foreach (var (layer, (visibility, linkage)) in Layers)
|
||||
{
|
||||
GUIFrame parent = new GUIFrame(new RectTransform(new Vector2(1f, 0.1f), layerList.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
@@ -4362,33 +4446,54 @@ namespace Barotrauma
|
||||
|
||||
GUILayoutGroup layerGroup = new GUILayoutGroup(new RectTransform(Vector2.One, parent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
|
||||
GUITickBox layerVisibleButton = new GUITickBox(new RectTransform(Vector2.One, layerGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), string.Empty)
|
||||
GUILayoutGroup layerVisibilityLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 1f), layerGroup.RectTransform), childAnchor: Anchor.Center);
|
||||
GUITickBox layerVisibleButton = new GUITickBox(new RectTransform(Vector2.One, layerVisibilityLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), string.Empty)
|
||||
{
|
||||
Selected = isVisible,
|
||||
Selected = visibility == LayerVisibility.Visible,
|
||||
OnSelected = box =>
|
||||
{
|
||||
if (!Layers.TryGetValue(layer, out bool _))
|
||||
if (!Layers.TryGetValue(layer, out LayerData data))
|
||||
{
|
||||
UpdateLayerPanel();
|
||||
return false;
|
||||
}
|
||||
|
||||
Layers[layer] = box.Selected;
|
||||
Layers[layer] = new LayerData(box.Selected ? LayerVisibility.Visible : LayerVisibility.Invisible, data.Linkage);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
GUILayoutGroup layerChainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.15f, 1f), layerGroup.RectTransform), childAnchor: Anchor.Center);
|
||||
GUITickBox layerChainButton = new GUITickBox(new RectTransform(Vector2.One, layerChainLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), string.Empty)
|
||||
{
|
||||
Selected = linkage == LayerLinkage.Linked,
|
||||
OnSelected = box =>
|
||||
{
|
||||
if (!Layers.TryGetValue(layer, out LayerData data))
|
||||
{
|
||||
UpdateLayerPanel();
|
||||
return false;
|
||||
}
|
||||
|
||||
Layers[layer] = new LayerData(data.Visible, box.Selected ? LayerLinkage.Linked : LayerLinkage.Unlinked);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
layerGroup.Recalculate();
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - layerVisibleButton.RectTransform.RelativeSize.X, 1f), layerGroup.RectTransform), layer, textAlignment: Alignment.CenterLeft)
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), layerGroup.RectTransform), layer, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
layerGroup.Recalculate();
|
||||
layerChainLayout.Recalculate();
|
||||
layerVisibilityLayout.Recalculate();
|
||||
}
|
||||
|
||||
layerList.RecalculateChildren();
|
||||
buttonHeaders.Recalculate();
|
||||
}
|
||||
|
||||
public void UpdateUndoHistoryPanel()
|
||||
@@ -4454,6 +4559,7 @@ namespace Barotrauma
|
||||
saveFrame = null;
|
||||
loadFrame = null;
|
||||
saveAssemblyFrame = null;
|
||||
snapToGridFrame = null;
|
||||
CreateUI();
|
||||
UpdateEntityList();
|
||||
}
|
||||
@@ -4501,6 +4607,7 @@ namespace Barotrauma
|
||||
hullVolumeFrame.Visible = MapEntity.SelectedList.Any(s => s is Hull);
|
||||
hullVolumeFrame.RectTransform.AbsoluteOffset = new Point(Math.Max(showEntitiesPanel.Rect.Right, previouslyUsedPanel.Rect.Right), 0);
|
||||
saveAssemblyFrame.Visible = MapEntity.SelectedList.Count > 0;
|
||||
snapToGridFrame.Visible = MapEntity.SelectedList.Count > 0;
|
||||
|
||||
var offset = cam.WorldView.Top - cam.ScreenToWorld(new Vector2(0, GameMain.GraphicsHeight - EntityMenu.Rect.Top)).Y;
|
||||
|
||||
@@ -4962,7 +5069,8 @@ namespace Barotrauma
|
||||
MouseDragStart = Vector2.Zero;
|
||||
}
|
||||
|
||||
if (!saveAssemblyFrame.Rect.Contains(PlayerInput.MousePosition) && dummyCharacter?.SelectedConstruction == null && !WiringMode && GUI.MouseOn == null)
|
||||
if (!saveAssemblyFrame.Rect.Contains(PlayerInput.MousePosition) && !snapToGridFrame.Rect.Contains(PlayerInput.MousePosition) &&
|
||||
dummyCharacter?.SelectedConstruction == null && !WiringMode && GUI.MouseOn == null)
|
||||
{
|
||||
if (layerList is { Visible: true } && GUI.KeyboardDispatcher.Subscriber == layerList)
|
||||
{
|
||||
@@ -5338,17 +5446,34 @@ namespace Barotrauma
|
||||
|
||||
public static bool IsLayerVisible(MapEntity entity)
|
||||
{
|
||||
if (!IsSubEditor()) { return true; }
|
||||
if (!IsSubEditor() || string.IsNullOrWhiteSpace(entity.Layer)) { return true; }
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entity.Layer)) { return true; }
|
||||
|
||||
if (!Layers.TryGetValue(entity.Layer, out bool isVisible))
|
||||
if (!Layers.TryGetValue(entity.Layer, out LayerData data))
|
||||
{
|
||||
Layers.TryAdd(entity.Layer, true);
|
||||
Layers.TryAdd(entity.Layer, LayerData.Default);
|
||||
return true;
|
||||
}
|
||||
|
||||
return isVisible;
|
||||
return data.Visible == LayerVisibility.Visible;
|
||||
}
|
||||
|
||||
public static bool IsLayerLinked(MapEntity entity)
|
||||
{
|
||||
if (!IsSubEditor() || string.IsNullOrWhiteSpace(entity.Layer)) { return false; }
|
||||
|
||||
if (!Layers.TryGetValue(entity.Layer, out LayerData data))
|
||||
{
|
||||
Layers.TryAdd(entity.Layer, LayerData.Default);
|
||||
return true;
|
||||
}
|
||||
|
||||
return data.Linkage == LayerLinkage.Linked;
|
||||
}
|
||||
|
||||
public static ImmutableHashSet<MapEntity> GetEntitiesInSameLayer(MapEntity entity)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entity.Layer)) { return ImmutableHashSet<MapEntity>.Empty; }
|
||||
return MapEntity.mapEntityList.Where(me => me.Layer == entity.Layer).ToImmutableHashSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ namespace Barotrauma
|
||||
|
||||
Character.Controlled = dummyCharacter;
|
||||
GameMain.World.ProcessChanges();
|
||||
TabMenu.selectedTab = TabMenu.InfoFrameTab.Talents;
|
||||
tabMenu = new TabMenu();
|
||||
}
|
||||
|
||||
|
||||
@@ -1157,7 +1157,7 @@ namespace Barotrauma
|
||||
public static void PlaySplashSound(Vector2 worldPosition, float strength)
|
||||
{
|
||||
if (SplashSounds.Count == 0) { return; }
|
||||
int splashIndex = MathHelper.Clamp((int)(strength + Rand.Range(-2, 2)), 0, SplashSounds.Count - 1);
|
||||
int splashIndex = MathHelper.Clamp((int)(strength + Rand.Range(-2.0f, 2.0f)), 0, SplashSounds.Count - 1);
|
||||
float range = 800.0f;
|
||||
var channel = SplashSounds[splashIndex].Play(1.0f, range, worldPosition, muffle: ShouldMuffleSound(Character.Controlled, worldPosition, range, null));
|
||||
}
|
||||
|
||||
@@ -148,14 +148,8 @@ namespace Barotrauma
|
||||
return t;
|
||||
}
|
||||
string fullPath = Path.GetFullPath(file);
|
||||
foreach (Sprite s in LoadedSprites)
|
||||
{
|
||||
if (s.FullPath == fullPath && s.texture != null && !s.texture.IsDisposed)
|
||||
{
|
||||
reusedSprite = s;
|
||||
return s.texture;
|
||||
}
|
||||
}
|
||||
reusedSprite = FindMatchingSprite(fullPath, requireTexture: true);
|
||||
if (reusedSprite != null) { return reusedSprite.texture; }
|
||||
|
||||
if (File.Exists(file))
|
||||
{
|
||||
@@ -176,6 +170,22 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Sprite FindMatchingSprite(string fullPath, bool requireTexture)
|
||||
{
|
||||
lock (list)
|
||||
{
|
||||
foreach (var wRef in list)
|
||||
{
|
||||
if (wRef.TryGetTarget(out Sprite sprite))
|
||||
{
|
||||
bool hasTexture = sprite.texture != null && !sprite.texture.IsDisposed;
|
||||
if (sprite.FullPath == fullPath && (hasTexture || !requireTexture)) { return sprite; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate = 0.0f, float scale = 1.0f, SpriteEffects spriteEffect = SpriteEffects.None)
|
||||
{
|
||||
this.Draw(spriteBatch, pos, Color.White, rotate, scale, spriteEffect);
|
||||
@@ -371,15 +381,9 @@ namespace Barotrauma
|
||||
//check if another sprite is using the same texture
|
||||
if (!string.IsNullOrEmpty(FilePath)) //file can be empty if the sprite is created directly from a Texture2D instance
|
||||
{
|
||||
lock (list)
|
||||
{
|
||||
foreach (Sprite s in LoadedSprites)
|
||||
{
|
||||
if (s.FullPath == FullPath) { return; }
|
||||
}
|
||||
}
|
||||
if (FindMatchingSprite(FullPath, requireTexture: false) != null) { return; }
|
||||
}
|
||||
|
||||
|
||||
//if not, free the texture
|
||||
if (texture != null)
|
||||
{
|
||||
|
||||
@@ -89,7 +89,17 @@ namespace Barotrauma
|
||||
|
||||
for (int j = 0; j < infoTextFiles.Count; j++)
|
||||
{
|
||||
List<string> xmlContent = ConvertInfoTextToXML(File.ReadAllLines(infoTextFiles[j], Encoding.UTF8), language);
|
||||
|
||||
List<string> xmlContent = null;
|
||||
try
|
||||
{
|
||||
xmlContent = ConvertInfoTextToXML(File.ReadAllLines(infoTextFiles[j], Encoding.UTF8), language);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + infoTextFiles[j], e);
|
||||
continue;
|
||||
}
|
||||
if (xmlContent == null)
|
||||
{
|
||||
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + infoTextFiles[j]);
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Barotrauma
|
||||
{
|
||||
int width = 4096; int height = 4096;
|
||||
|
||||
Rectangle subDimensions = sub.Borders;
|
||||
Rectangle subDimensions = sub.CalculateDimensions(false);
|
||||
Vector2 viewPos = subDimensions.Center.ToVector2();
|
||||
float scale = Math.Min(width / (float)subDimensions.Width, height / (float)subDimensions.Height);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Version>0.16.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Version>0.16.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Version>0.16.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Version>0.16.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Version>0.16.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -28,11 +28,11 @@ namespace Barotrauma
|
||||
if (!CheatsEnabled && IsCheat)
|
||||
{
|
||||
NewMessage("Client \"" + client.Name + "\" attempted to use the command \"" + names[0] + "\". Cheats must be enabled using \"enablecheats\" before the command can be used.", Color.Red);
|
||||
GameMain.Server.SendConsoleMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", client);
|
||||
GameMain.Server.SendConsoleMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", client, Color.Red);
|
||||
|
||||
#if USE_STEAM
|
||||
NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red);
|
||||
GameMain.Server.SendConsoleMessage("Enabling cheats will disable Steam achievements during this play session.", client);
|
||||
GameMain.Server.SendConsoleMessage("Enabling cheats will disable Steam achievements during this play session.", client, Color.Red);
|
||||
#endif
|
||||
|
||||
return;
|
||||
@@ -367,7 +367,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client, Color.Red);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1046,12 +1046,12 @@ namespace Barotrauma
|
||||
}));
|
||||
AssignOnClientRequestExecute("clientlist", (Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("***************", client);
|
||||
GameMain.Server.SendConsoleMessage("***************", client, Color.Cyan);
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.EndPointString + $", ping {c.Ping} ms", client);
|
||||
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.EndPointString + $", ping {c.Ping} ms", client, Color.Cyan);
|
||||
}
|
||||
GameMain.Server.SendConsoleMessage("***************", client);
|
||||
GameMain.Server.SendConsoleMessage("***************", client, Color.Cyan);
|
||||
});
|
||||
|
||||
commands.Add(new Command("enablecheats", "enablecheats: Enables cheat commands and disables Steam achievements during this play session.", (string[] args) =>
|
||||
@@ -1164,13 +1164,13 @@ namespace Barotrauma
|
||||
if (GameMain.Server == null || args.Length == 0) return;
|
||||
if (!int.TryParse(args[0], out int maxPlayers))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid player count.", client);
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid player count.", client, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxPlayers > NetConfig.MaxPlayers)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Setting the maximum amount of players to {maxPlayers} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", client);
|
||||
GameMain.Server.SendConsoleMessage($"Setting the maximum amount of players to {maxPlayers} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", client, Color.Red);
|
||||
maxPlayers = NetConfig.MaxPlayers;
|
||||
}
|
||||
|
||||
@@ -1455,7 +1455,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid ban duration.", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid ban duration.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1575,7 +1575,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -1599,7 +1599,7 @@ namespace Barotrauma
|
||||
if (Submarine.MainSub == null || Level.Loaded == null) return;
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("The teleportsub command is unavailable in outpost levels!", client);
|
||||
GameMain.Server.SendConsoleMessage("The teleportsub command is unavailable in outpost levels!", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1623,7 +1623,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!(GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active.", client);
|
||||
GameMain.Server.SendConsoleMessage("No campaign active.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
mpCampaign.LastUpdateID++;
|
||||
@@ -1671,13 +1671,13 @@ namespace Barotrauma
|
||||
a.Identifier.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (afflictionPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client);
|
||||
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!float.TryParse(args[1], out float afflictionStrength))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid affliction strength.", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid affliction strength.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1760,7 +1760,7 @@ namespace Barotrauma
|
||||
c.DisplayName.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (talentPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Couldn't find the talent \"" + args[0] + "\".", client);
|
||||
GameMain.Server.SendConsoleMessage("Couldn't find the talent \"" + args[0] + "\".", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
targetCharacter.GiveTalent(talentPrefab);
|
||||
@@ -1786,12 +1786,12 @@ namespace Barotrauma
|
||||
var job = JobPrefab.Prefabs.Find(jp => jp.Name != null && jp.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (job == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Failed to find the job \"{args[0]}\".", client);
|
||||
GameMain.Server.SendConsoleMessage($"Failed to find the job \"{args[0]}\".", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(job.Identifier, out TalentTree talentTree))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"No talents configured for the job \"{args[0]}\".", client);
|
||||
GameMain.Server.SendConsoleMessage($"No talents configured for the job \"{args[0]}\".", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
talentTrees.Add(talentTree);
|
||||
@@ -1858,6 +1858,10 @@ namespace Barotrauma
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character killedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
if (killedCharacter == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the specified character.", client, Color.Red);
|
||||
}
|
||||
killedCharacter?.SetAllDamage(200.0f, 0.0f, 0.0f);
|
||||
}
|
||||
);
|
||||
@@ -1873,6 +1877,10 @@ namespace Barotrauma
|
||||
GameMain.Server.SetClientCharacter(client, character);
|
||||
client.SpectateOnly = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the specified character.", client, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1899,7 +1907,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid difficulty setting (enter a value between 0-100)", client);
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid difficulty setting (enter a value between 0-100)", client, Color.Red);
|
||||
NewMessage(args[0] + " is not a valid difficulty setting (enter a value between 0-100)", Color.Red);
|
||||
}
|
||||
}
|
||||
@@ -1923,7 +1931,7 @@ namespace Barotrauma
|
||||
ClientPermissions permission = ClientPermissions.None;
|
||||
if (!Enum.TryParse(perm, true, out permission))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1955,7 +1963,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke permissions from the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke permissions from the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1964,7 +1972,7 @@ namespace Barotrauma
|
||||
ClientPermissions permission = ClientPermissions.None;
|
||||
if (!Enum.TryParse(perm, true, out permission))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
client.RemovePermission(permission);
|
||||
@@ -1988,7 +1996,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the rank of the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the rank of the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1996,7 +2004,7 @@ namespace Barotrauma
|
||||
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.Equals(rank, StringComparison.OrdinalIgnoreCase));
|
||||
if (preset == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Rank \"" + rank + "\" not found.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Rank \"" + rank + "\" not found.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2016,12 +2024,12 @@ namespace Barotrauma
|
||||
var client = FindClient(args[0]);
|
||||
if (client == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the command permissions of the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the command permissions of the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2040,7 +2048,7 @@ namespace Barotrauma
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommands[i]));
|
||||
if (matchingCommand == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2078,7 +2086,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke command permissions from the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke command permissions from the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
List<Command> revokedCommands = new List<Command>();
|
||||
@@ -2096,7 +2104,7 @@ namespace Barotrauma
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommands[i]));
|
||||
if (matchingCommand == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2176,7 +2184,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2189,7 +2197,7 @@ namespace Barotrauma
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
|
||||
if (client == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2206,17 +2214,18 @@ namespace Barotrauma
|
||||
if (args.Length == 0) { return; }
|
||||
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
if (int.TryParse(args[0], out int money))
|
||||
{
|
||||
campaign.Money += money;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
campaign.LastUpdateID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"\"{args[0]}\" is not a valid numeric value.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage($"\"{args[0]}\" is not a valid numeric value.", senderClient, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2226,7 +2235,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!(GameMain.GameSession?.GameMode is CampaignMode campaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2234,7 +2243,7 @@ namespace Barotrauma
|
||||
if (args.Length < 1 || !int.TryParse(args[0], out destinationIndex)) return;
|
||||
if (destinationIndex < 0 || destinationIndex >= campaign.Map.CurrentLocation.Connections.Count)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Index out of bounds!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Index out of bounds!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
Location location = campaign.Map.CurrentLocation.Connections[destinationIndex].OtherLocation(campaign.Map.CurrentLocation);
|
||||
@@ -2251,14 +2260,41 @@ namespace Barotrauma
|
||||
NewMessage(tag, Color.Yellow);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
commands.Add(new Command("sendchatmessage", "Sends a chat message with specified type and color.", (string[] args) =>
|
||||
{
|
||||
if (args.Length < 2) { return; }
|
||||
|
||||
ChatMessageType chatMessageType = ChatMessageType.Default;
|
||||
Color? chatMessageColor = null;
|
||||
|
||||
if (args.Length >= 3 && int.TryParse(args[2], out int result))
|
||||
{
|
||||
chatMessageType = (ChatMessageType)result;
|
||||
}
|
||||
|
||||
if (args.Length >= 7 &&
|
||||
int.TryParse(args[3], out int r) &&
|
||||
int.TryParse(args[4], out int g) &&
|
||||
int.TryParse(args[5], out int b) &&
|
||||
int.TryParse(args[6], out int a))
|
||||
{
|
||||
chatMessageColor = new Color(r, g, b, a);
|
||||
}
|
||||
|
||||
foreach (var client in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(ChatMessage.Create(args[0], args[1], chatMessageType, null, null, textColor: chatMessageColor), client);
|
||||
}
|
||||
}));
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"setskill",
|
||||
(senderClient, cursorWorldPos, args) =>
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Missing arguments. Expected at least 2 but got {args.Length} (skill, level, name)", senderClient);
|
||||
GameMain.Server.SendConsoleMessage($"Missing arguments. Expected at least 2 but got {args.Length} (skill, level, name)", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2268,7 +2304,7 @@ namespace Barotrauma
|
||||
|
||||
if (character?.Info?.Job == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Character is not valid.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Character is not valid.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2295,7 +2331,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"{levelString} is not a valid level. Expected number or \"max\".", senderClient);
|
||||
GameMain.Server.SendConsoleMessage($"{levelString} is not a valid level. Expected number or \"max\".", senderClient, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2389,7 +2425,7 @@ namespace Barotrauma
|
||||
if (string.IsNullOrWhiteSpace(command)) return;
|
||||
if (!client.HasPermission(ClientPermissions.ConsoleCommands) && client.Connection != GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use console commands!", client);
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use console commands!", client, Color.Red);
|
||||
GameServer.Log(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" without a permission to use console commands.", ServerLog.MessageType.ConsoleUsage);
|
||||
return;
|
||||
}
|
||||
@@ -2398,19 +2434,19 @@ namespace Barotrauma
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommand[0].ToLowerInvariant()));
|
||||
if (matchingCommand != null && !client.PermittedConsoleCommands.Contains(matchingCommand) && client.Connection != GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use the command\"" + matchingCommand.names[0] + "\"!", client);
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use the command\"" + matchingCommand.names[0] + "\"!", client, Color.Red);
|
||||
GameServer.Log(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" without a permission to use the command.", ServerLog.MessageType.ConsoleUsage);
|
||||
return;
|
||||
}
|
||||
else if (matchingCommand == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Command \"" + splitCommand[0] + "\" not found.", client);
|
||||
GameMain.Server.SendConsoleMessage("Command \"" + splitCommand[0] + "\" not found.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MathUtils.IsValid(cursorWorldPos))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client);
|
||||
GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client, Color.Red);
|
||||
NewMessage(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" with invalid cursor position.", Color.White);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma
|
||||
public static GameServer Server;
|
||||
public static NetworkMember NetworkMember
|
||||
{
|
||||
get { return Server as NetworkMember; }
|
||||
get { return Server; }
|
||||
}
|
||||
|
||||
public static GameSession GameSession;
|
||||
@@ -64,6 +64,9 @@ namespace Barotrauma
|
||||
|
||||
private static Stopwatch stopwatch;
|
||||
|
||||
private static Queue<int> prevUpdateRates = new Queue<int>();
|
||||
private static int updateCount = 0;
|
||||
|
||||
private static ContentPackage vanillaContent;
|
||||
public static ContentPackage VanillaContent
|
||||
{
|
||||
@@ -364,6 +367,8 @@ namespace Barotrauma
|
||||
DebugConsole.NewMessage("WARNING: Stopwatch frequency under 1500 ticks per second. Expect significant syncing accuracy issues.", Color.Yellow);
|
||||
}
|
||||
|
||||
Stopwatch performanceCounterTimer = Stopwatch.StartNew();
|
||||
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
long prevTicks = stopwatch.ElapsedTicks;
|
||||
while (ShouldRun)
|
||||
@@ -371,9 +376,11 @@ namespace Barotrauma
|
||||
long currTicks = stopwatch.ElapsedTicks;
|
||||
double elapsedTime = Math.Max(currTicks - prevTicks, 0) / frequency;
|
||||
Timing.Accumulator += elapsedTime;
|
||||
if (Timing.Accumulator > 1.0)
|
||||
if (Timing.Accumulator > Timing.AccumulatorMax)
|
||||
{
|
||||
//prevent spiral of death
|
||||
//prevent spiral of death:
|
||||
//if the game's running too slowly then we have no choice but to skip a bunch of steps
|
||||
//otherwise it snowballs and becomes unplayable
|
||||
Timing.Accumulator = Timing.Step;
|
||||
}
|
||||
prevTicks = currTicks;
|
||||
@@ -392,6 +399,7 @@ namespace Barotrauma
|
||||
CoroutineManager.Update((float)Timing.Step, (float)Timing.Step);
|
||||
|
||||
Timing.Accumulator -= Timing.Step;
|
||||
updateCount++;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
@@ -407,10 +415,34 @@ namespace Barotrauma
|
||||
DebugConsole.UpdateCommandLine((int)(Timing.Accumulator * 800));
|
||||
#endif
|
||||
|
||||
int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency) * 1000.0);
|
||||
int frameTime = (int)((stopwatch.ElapsedTicks - prevTicks) / frequency * 1000.0);
|
||||
frameTime = Math.Max(0, frameTime);
|
||||
|
||||
Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime) / 2, 0));
|
||||
|
||||
if (performanceCounterTimer.ElapsedMilliseconds > 1000)
|
||||
{
|
||||
int updateRate = (int)Math.Round(updateCount / (double)(performanceCounterTimer.ElapsedMilliseconds / 1000.0));
|
||||
prevUpdateRates.Enqueue(updateRate);
|
||||
if (prevUpdateRates.Count >= 10)
|
||||
{
|
||||
int avgUpdateRate = (int)prevUpdateRates.Average();
|
||||
if (avgUpdateRate < Timing.FixedUpdateRate * 0.98 && GameSession != null && Timing.TotalTime > GameSession.RoundStartTime + 1.0)
|
||||
{
|
||||
DebugConsole.AddWarning($"Running slowly ({avgUpdateRate} updates/s)!");
|
||||
foreach (Client c in Server.ConnectedClients)
|
||||
{
|
||||
if (c.Connection == Server.OwnerConnection || c.Permissions != ClientPermissions.None)
|
||||
{
|
||||
Server.SendConsoleMessage($"Server running slowly ({avgUpdateRate} updates/s)!", c, Color.Orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
prevUpdateRates.Clear();
|
||||
}
|
||||
performanceCounterTimer.Restart();
|
||||
updateCount = 0;
|
||||
}
|
||||
}
|
||||
stopwatch.Stop();
|
||||
|
||||
@@ -429,8 +461,9 @@ namespace Barotrauma
|
||||
public static void ResetFrameTime()
|
||||
{
|
||||
Timing.Accumulator = 0.0f;
|
||||
stopwatch?.Reset();
|
||||
stopwatch?.Start();
|
||||
stopwatch?.Restart();
|
||||
prevUpdateRates.Clear();
|
||||
updateCount = 0;
|
||||
}
|
||||
|
||||
public CoroutineHandle ShowLoading(IEnumerable<CoroutineStatus> loader, bool waitKeyHit = true)
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace Barotrauma
|
||||
SoldItems.Add(item);
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier);
|
||||
}
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
@@ -285,11 +285,15 @@ namespace Barotrauma
|
||||
break;
|
||||
case TransitionType.ProgressToNextLocation:
|
||||
Map.MoveToNextLocation();
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
case TransitionType.End:
|
||||
EndCampaign();
|
||||
IsFirstRound = true;
|
||||
break;
|
||||
case TransitionType.ProgressToNextEmptyLocation:
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
}
|
||||
|
||||
Map.ProgressWorld(transitionType, (float)(Timing.TotalTime - GameMain.GameSession.RoundStartTime));
|
||||
@@ -697,6 +701,7 @@ namespace Barotrauma
|
||||
{
|
||||
this.PurchasedHullRepairs = true;
|
||||
Money -= hullRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
}
|
||||
else if (!purchasedHullRepairs)
|
||||
{
|
||||
@@ -710,6 +715,7 @@ namespace Barotrauma
|
||||
{
|
||||
this.PurchasedItemRepairs = true;
|
||||
Money -= itemRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
@@ -728,6 +734,7 @@ namespace Barotrauma
|
||||
{
|
||||
this.PurchasedLostShuttles = true;
|
||||
Money -= shuttleRetrieveCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(shuttleRetrieveCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
@@ -998,7 +1005,9 @@ namespace Barotrauma
|
||||
new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
|
||||
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
|
||||
new XAttribute("cheatsenabled", CheatsEnabled));
|
||||
|
||||
modeElement.Add(Settings.Save());
|
||||
modeElement.Add(SaveStats());
|
||||
CampaignMetadata?.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
internal partial class Growable
|
||||
{
|
||||
private const int serverHealthUpdateDelay = 10;
|
||||
private int serverHealthUpdateTimer;
|
||||
|
||||
partial void LoadVines(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class WifiComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger(Channel, MinChannel, MaxChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
msg.Write(Sender.ID);
|
||||
}
|
||||
msg.Write(customTextColor != null);
|
||||
if (customTextColor != null)
|
||||
{
|
||||
msg.WriteColorR8G8B8A8(customTextColor.Value);
|
||||
}
|
||||
msg.WritePadBits();
|
||||
if (Type == ChatMessageType.ServerMessageBoxInGame)
|
||||
{
|
||||
|
||||
@@ -726,7 +726,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
break;
|
||||
case ClientPacketHeader.REQUEST_STARTGAMEFINALIZE:
|
||||
if (gameStarted && connectedClient != null)
|
||||
if (connectedClient == null)
|
||||
{
|
||||
DebugConsole.AddWarning("Received a REQUEST_STARTGAMEFINALIZE message. Client not connected, ignoring the message.");
|
||||
}
|
||||
else if (!gameStarted)
|
||||
{
|
||||
DebugConsole.AddWarning("Received a REQUEST_STARTGAMEFINALIZE message. Game not started, ignoring the message.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendRoundStartFinalize(connectedClient);
|
||||
}
|
||||
@@ -746,7 +754,7 @@ namespace Barotrauma.Networking
|
||||
string seed = inc.ReadString();
|
||||
string subName = inc.ReadString();
|
||||
string subHash = inc.ReadString();
|
||||
CampaignSettings settings = new CampaignSettings(inc);
|
||||
CampaignSettings settings = new CampaignSettings(inc);
|
||||
|
||||
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
|
||||
|
||||
@@ -769,6 +777,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ServerSettings.RadiationEnabled = settings.RadiationEnabled;
|
||||
ServerSettings.MaxMissionCount = settings.MaxMissionCount;
|
||||
ServerSettings.SaveSettings();
|
||||
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed, settings);
|
||||
}
|
||||
}
|
||||
@@ -1904,7 +1913,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - outmsg.LengthBytes;
|
||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||
|
||||
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
@@ -1927,7 +1936,11 @@ namespace Barotrauma.Networking
|
||||
warningMsg +=
|
||||
" Settings buffer size: " + settingsBuf.LengthBytes + " bytes\n";
|
||||
}
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.ThrowError(warningMsg);
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
|
||||
}
|
||||
|
||||
@@ -1943,12 +1956,16 @@ namespace Barotrauma.Networking
|
||||
//these large initial messages until the client acknowledges receiving them
|
||||
c.LastRecvLobbyUpdate++;
|
||||
|
||||
SendVoteStatus(new List<Client>() { c });
|
||||
}
|
||||
else
|
||||
{
|
||||
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
if (isInitialUpdate)
|
||||
{
|
||||
SendVoteStatus(new List<Client>() { c });
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteChatMessages(IWriteMessage outmsg, Client c)
|
||||
@@ -2893,9 +2910,9 @@ namespace Barotrauma.Networking
|
||||
SendDirectChatMessage(msg, recipient);
|
||||
}
|
||||
|
||||
public void SendConsoleMessage(string txt, Client recipient)
|
||||
public void SendConsoleMessage(string txt, Client recipient, Color? color = null)
|
||||
{
|
||||
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Console, null);
|
||||
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Console, sender: null, textColor: color);
|
||||
SendDirectChatMessage(msg, recipient);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,10 +115,14 @@ namespace Barotrauma.Networking
|
||||
return ShouldStartRespawnCountdown(characterToRespawnCount);
|
||||
}
|
||||
|
||||
private int GetMinCharactersToRespawn()
|
||||
{
|
||||
return Math.Max((int)(GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio), 1);
|
||||
}
|
||||
|
||||
private bool ShouldStartRespawnCountdown(int characterToRespawnCount)
|
||||
{
|
||||
int totalCharacterCount = GameMain.Server.ConnectedClients.Count;
|
||||
return (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||
return characterToRespawnCount >= GetMinCharactersToRespawn();
|
||||
}
|
||||
|
||||
partial void UpdateWaiting(float deltaTime)
|
||||
@@ -129,7 +133,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
pendingRespawnCount = GetClientsToRespawn().Count();
|
||||
requiredRespawnCount = (int)Math.Max((float)GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||
requiredRespawnCount = GetMinCharactersToRespawn();
|
||||
if (pendingRespawnCount != prevPendingRespawnCount ||
|
||||
requiredRespawnCount != prevRequiredRespawnCount)
|
||||
{
|
||||
|
||||
@@ -223,11 +223,6 @@ namespace Barotrauma.Networking
|
||||
AutoRestart = autoRestart;
|
||||
}
|
||||
|
||||
RadiationEnabled = incMsg.ReadBoolean();
|
||||
|
||||
int maxMissionCount = MaxMissionCount + incMsg.ReadByte() - 1;
|
||||
MaxMissionCount = MathHelper.Clamp(maxMissionCount, CampaignSettings.MinMissionCountLimit, CampaignSettings.MaxMissionCountLimit);
|
||||
|
||||
changed |= true;
|
||||
UpdateFlag(NetFlags.Misc);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.16.0.0</Version>
|
||||
<Version>0.16.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace Barotrauma
|
||||
{
|
||||
targetingTag = "dead";
|
||||
}
|
||||
else if (AIParams.TryGetTarget(targetCharacter.CharacterHealth.GetActiveAfflictionTags(), out CharacterParams.TargetParams tp) && tp.Threshold > Character.GetDamageDoneByAttacker(targetCharacter))
|
||||
else if (AIParams.TryGetTarget(targetCharacter.CharacterHealth.GetActiveAfflictionTags(), out CharacterParams.TargetParams tp) && tp.Threshold >= Character.GetDamageDoneByAttacker(targetCharacter))
|
||||
{
|
||||
targetingTag = tp.Tag;
|
||||
}
|
||||
@@ -678,7 +678,10 @@ namespace Barotrauma
|
||||
return a.Damage >= selectedTargetingParams.Threshold;
|
||||
}
|
||||
Character attacker = targetCharacter.LastAttackers.LastOrDefault(IsValid)?.Character;
|
||||
if (attacker != null)
|
||||
//if the attacker has the same targeting tag as the character we're protecting, we can't change the TargetState
|
||||
//otherwise e.g. a pet that's set to follow humans would start attacking all humans (and other pets, since they're considered part of the same group) when a hostile human attacks it
|
||||
//TODO: a way for pets to differentiate hostile and friendly humans?
|
||||
if (attacker?.AiTarget != null && !targetCharacter.SpeciesName.Equals(GetTargetingTag(attacker.AiTarget), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Attack the character that attacked the target we are protecting
|
||||
ChangeTargetState(attacker, AIState.Attack, selectedTargetingParams.Priority * 2);
|
||||
@@ -1598,7 +1601,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
sweepTimer = Rand.Range(-1000, 1000) * selectedTargetingParams.SweepSpeed;
|
||||
sweepTimer = Rand.Range(-1000f, 1000f) * selectedTargetingParams.SweepSpeed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2305,7 +2308,7 @@ namespace Barotrauma
|
||||
|
||||
if (item.Condition <= 0.0f)
|
||||
{
|
||||
if (!wasBroken) { PetBehavior?.OnEat(item.GetTags(), 1.0f); }
|
||||
if (!wasBroken) { PetBehavior?.OnEat(item); }
|
||||
Entity.Spawner.AddToRemoveQueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ namespace Barotrauma
|
||||
Character.AnimController.HeadInWater ||
|
||||
Character.Submarine == null ||
|
||||
(Character.Submarine.TeamID != Character.TeamID && !Character.IsEscorted) ||
|
||||
ObjectiveManager.CurrentOrders.Any(o => o.Objective.KeepDivingGearOn) ||
|
||||
!ObjectiveManager.IsCurrentObjective<AIObjectiveIdle>() && ObjectiveManager.CurrentOrders.Any(o => o.Objective.KeepDivingGearOn) ||
|
||||
ObjectiveManager.CurrentObjective.GetSubObjectivesRecursive(true).Any(o => o.KeepDivingGearOn) ||
|
||||
Character.CurrentHull.OxygenPercentage < HULL_LOW_OXYGEN_PERCENTAGE + 10;
|
||||
bool IsOrderedToWait() => Character.IsOnPlayerTeam && ObjectiveManager.CurrentOrder is AIObjectiveGoTo goTo && goTo.Target == Character;
|
||||
@@ -1090,7 +1090,6 @@ namespace Barotrauma
|
||||
|
||||
private void RespondToAttack(Character attacker, AttackResult attackResult)
|
||||
{
|
||||
float minorDamageThreshold = 10;
|
||||
float healAmount = 0.0f;
|
||||
if (attacker != null)
|
||||
{
|
||||
@@ -1099,7 +1098,7 @@ namespace Barotrauma
|
||||
// excluding poisons etc
|
||||
float realDamage = attackResult.Damage - healAmount;
|
||||
// including poisons etc
|
||||
float totalDamage = realDamage - healAmount;
|
||||
float totalDamage = realDamage;
|
||||
if (attackResult.Afflictions != null)
|
||||
{
|
||||
foreach (Affliction affliction in attackResult.Afflictions)
|
||||
@@ -1140,6 +1139,13 @@ namespace Barotrauma
|
||||
}
|
||||
bool isAttackerInfected = false;
|
||||
bool isAttackerFightingEnemy = false;
|
||||
float minorDamageThreshold = 1;
|
||||
float majorDamageThreshold = 20;
|
||||
if (attacker.TeamID == Character.TeamID)
|
||||
{
|
||||
minorDamageThreshold = 10;
|
||||
majorDamageThreshold = 40;
|
||||
}
|
||||
if (IsFriendly(attacker))
|
||||
{
|
||||
if (attacker.AnimController.Anim == Barotrauma.AnimController.Animation.CPR && attacker.SelectedCharacter == Character)
|
||||
@@ -1148,11 +1154,11 @@ namespace Barotrauma
|
||||
// Should not cancel any existing ai objectives (so that if the character attacked you and then helped, we still would want to retaliate).
|
||||
return;
|
||||
}
|
||||
float cumulativeDamage = Character.GetDamageDoneByAttacker(attacker);
|
||||
float cumulativeDamage = realDamage + Character.GetDamageDoneByAttacker(attacker);
|
||||
bool isAccidental = attacker.IsBot && !IsMentallyUnstable && !attacker.AIController.IsMentallyUnstable && Character.CombatAction == null;
|
||||
if (isAccidental)
|
||||
{
|
||||
if (!Character.IsSecurity && cumulativeDamage > 1)
|
||||
if (!Character.IsSecurity && cumulativeDamage > minorDamageThreshold)
|
||||
{
|
||||
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, attacker);
|
||||
}
|
||||
@@ -1161,7 +1167,7 @@ namespace Barotrauma
|
||||
{
|
||||
isAttackerInfected = attacker.CharacterHealth.GetAfflictionStrength("alieninfection") > 0;
|
||||
// Inform other NPCs
|
||||
if (isAttackerInfected || cumulativeDamage > 1 || totalDamage >= minorDamageThreshold)
|
||||
if (isAttackerInfected || cumulativeDamage > minorDamageThreshold || totalDamage > minorDamageThreshold)
|
||||
{
|
||||
if (GameMain.IsMultiplayer || !attacker.IsPlayer || Character.TeamID != attacker.TeamID)
|
||||
{
|
||||
@@ -1170,27 +1176,36 @@ namespace Barotrauma
|
||||
}
|
||||
if (Character.IsBot)
|
||||
{
|
||||
if (ObjectiveManager.CurrentObjective is AIObjectiveFightIntruders) { return; }
|
||||
if (attacker.IsPlayer)
|
||||
var combatMode = DetermineCombatMode(Character, cumulativeDamage);
|
||||
if (attacker.IsPlayer && !Character.IsInstigator && !ObjectiveManager.IsCurrentObjective<AIObjectiveCombat>())
|
||||
{
|
||||
if (Character.IsSecurity)
|
||||
switch (combatMode)
|
||||
{
|
||||
if (attacker.TeamID != Character.TeamID && cumulativeDamage > 1 || cumulativeDamage > minorDamageThreshold)
|
||||
{
|
||||
Character.Speak(TextManager.Get("dialogattackedbyfriendlysecurityarrest"), null, 0.50f, "attackedbyfriendlysecurityarrest", minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Character.Speak(TextManager.Get("dialogattackedbyfriendlysecurityresponse"), null, 0.50f, "attackedbyfriendlysecurityresponse", minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
}
|
||||
else if (!Character.IsInstigator && cumulativeDamage > 1)
|
||||
{
|
||||
Character.Speak(TextManager.Get("DialogAttackedByFriendly"), null, 0.50f, "attackedbyfriendly", minDurationBetweenSimilar: 30.0f);
|
||||
case AIObjectiveCombat.CombatMode.Defensive:
|
||||
case AIObjectiveCombat.CombatMode.Retreat:
|
||||
if (Character.IsSecurity)
|
||||
{
|
||||
Character.Speak(TextManager.Get("dialogattackedbyfriendlysecurityresponse"), null, 0.5f, "attackedbyfriendlysecurityresponse", minDurationBetweenSimilar: 10.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Character.Speak(TextManager.Get("DialogAttackedByFriendly"), null, 0.5f, "attackedbyfriendly", minDurationBetweenSimilar: 10.0f);
|
||||
}
|
||||
break;
|
||||
case AIObjectiveCombat.CombatMode.Offensive:
|
||||
case AIObjectiveCombat.CombatMode.Arrest:
|
||||
Character.Speak(TextManager.Get("dialogattackedbyfriendlysecurityarrest"), null, 0.5f, "attackedbyfriendlysecurityarrest", minDurationBetweenSimilar: 10.0f);
|
||||
break;
|
||||
case AIObjectiveCombat.CombatMode.None:
|
||||
if (Character.IsSecurity && realDamage > 1)
|
||||
{
|
||||
Character.Speak(TextManager.Get("dialogattackedbyfriendlysecurityresponse"), null, 0.5f, "attackedbyfriendlysecurityresponse", minDurationBetweenSimilar: 10.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the attacker is using a low damage and high frequency weapon like a repair tool, we shouldn't use any delay.
|
||||
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage), attacker, delay: realDamage > 1 ? GetReactionTime() : 0);
|
||||
AddCombatObjective(combatMode, attacker, delay: realDamage > 1 ? GetReactionTime() : 0);
|
||||
}
|
||||
if (!isAttackerFightingEnemy)
|
||||
{
|
||||
@@ -1203,15 +1218,15 @@ namespace Barotrauma
|
||||
if (Character.Submarine != null && Character.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
|
||||
{
|
||||
// Non-friendly
|
||||
InformOtherNPCs(Character.GetDamageDoneByAttacker(attacker));
|
||||
InformOtherNPCs();
|
||||
}
|
||||
if (Character.IsBot)
|
||||
{
|
||||
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage: realDamage), attacker);
|
||||
AddCombatObjective(DetermineCombatMode(Character), attacker);
|
||||
}
|
||||
}
|
||||
|
||||
void InformOtherNPCs(float cumulativeDamage)
|
||||
void InformOtherNPCs(float cumulativeDamage = 0)
|
||||
{
|
||||
foreach (Character otherCharacter in Character.CharacterList)
|
||||
{
|
||||
@@ -1238,7 +1253,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
AIObjectiveCombat.CombatMode DetermineCombatMode(Character c, float cumulativeDamage, bool isWitnessing = false)
|
||||
AIObjectiveCombat.CombatMode DetermineCombatMode(Character c, float cumulativeDamage = 0, bool isWitnessing = false)
|
||||
{
|
||||
if (!IsFriendly(attacker))
|
||||
{
|
||||
@@ -1258,7 +1273,6 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
float dmgThreshold = attacker.TeamID == Character.TeamID ? 50 : minorDamageThreshold;
|
||||
if (isAttackerInfected)
|
||||
{
|
||||
cumulativeDamage = 100;
|
||||
@@ -1266,8 +1280,7 @@ namespace Barotrauma
|
||||
if (GameMain.IsSingleplayer && attacker.IsPlayer && Character.TeamID == attacker.TeamID)
|
||||
{
|
||||
// Bots in the player team never act aggressively in single player when attacked by the player
|
||||
dmgThreshold = minorDamageThreshold;
|
||||
return cumulativeDamage > dmgThreshold ? AIObjectiveCombat.CombatMode.Retreat : AIObjectiveCombat.CombatMode.None;
|
||||
return cumulativeDamage > minorDamageThreshold ? AIObjectiveCombat.CombatMode.Retreat : AIObjectiveCombat.CombatMode.None;
|
||||
}
|
||||
if (Character.Submarine == null || !Character.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
|
||||
{
|
||||
@@ -1308,21 +1321,25 @@ namespace Barotrauma
|
||||
// Already targeting the attacker -> treat as a more serious threat.
|
||||
cumulativeDamage *= 2;
|
||||
}
|
||||
if (cumulativeDamage > dmgThreshold)
|
||||
if (cumulativeDamage > majorDamageThreshold)
|
||||
{
|
||||
if (c.IsSecurity)
|
||||
{
|
||||
return c.IsSecurity ? AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Arrest;
|
||||
return AIObjectiveCombat.CombatMode.Offensive;
|
||||
}
|
||||
else
|
||||
{
|
||||
return c == Character ? AIObjectiveCombat.CombatMode.Defensive : AIObjectiveCombat.CombatMode.Retreat;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (cumulativeDamage > minorDamageThreshold)
|
||||
{
|
||||
return c.IsSecurity ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Retreat;
|
||||
}
|
||||
else
|
||||
{
|
||||
return AIObjectiveCombat.CombatMode.None;
|
||||
}
|
||||
}
|
||||
|
||||
Character FindInstigator()
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Barotrauma
|
||||
private float holdFireTimer;
|
||||
private bool hasAimed;
|
||||
private bool isLethalWeapon;
|
||||
private bool AllowCoolDown => !IsOffensiveOrArrest || Mode != initialMode;
|
||||
private bool AllowCoolDown => !IsOffensiveOrArrest || Mode != initialMode || character.TeamID == Enemy.TeamID;
|
||||
|
||||
public Character Enemy { get; private set; }
|
||||
public bool HoldPosition { get; set; }
|
||||
@@ -143,7 +143,7 @@ namespace Barotrauma
|
||||
{
|
||||
Mode = CombatMode.Retreat;
|
||||
}
|
||||
spreadTimer = Rand.Range(-10, 10);
|
||||
spreadTimer = Rand.Range(-10f, 10f);
|
||||
HumanAIController.SortTimer = 0;
|
||||
}
|
||||
|
||||
@@ -1177,7 +1177,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private void SpeakNoWeapons() => Speak("dialogcombatnoweapons", delay: 0, minDuration: 30);
|
||||
private void AskHelp() => Speak("dialogcombatretreating", delay: Rand.Range(0, 1), minDuration: 20);
|
||||
private void AskHelp() => Speak("dialogcombatretreating", delay: Rand.Range(0f, 1f), minDuration: 20);
|
||||
|
||||
private void Speak(string textIdentifier, float delay, float minDuration)
|
||||
{
|
||||
|
||||
@@ -43,7 +43,6 @@ namespace Barotrauma
|
||||
private readonly float minDistance = 50;
|
||||
private readonly float seekGapsInterval = 1;
|
||||
private float seekGapsTimer;
|
||||
private bool cannotFollow;
|
||||
|
||||
/// <summary>
|
||||
/// Display units
|
||||
@@ -52,6 +51,11 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsFollowOrderObjective && Target is Character targetCharacter && (targetCharacter.CurrentHull == null) != (character.CurrentHull == null))
|
||||
{
|
||||
// Keep close when the target is going inside/outside
|
||||
return minDistance;
|
||||
}
|
||||
float dist = _closeEnough * CloseEnoughMultiplier;
|
||||
float extraMultiplier = Math.Clamp(CloseEnoughMultiplier * 0.6f, 1, 3);
|
||||
if (character.AnimController.InWater)
|
||||
@@ -288,28 +292,16 @@ namespace Barotrauma
|
||||
{
|
||||
TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit: false, objectiveManager),
|
||||
onAbandon: () => Abandon = true,
|
||||
onCompleted: () =>
|
||||
{
|
||||
cannotFollow = false;
|
||||
RemoveSubObjective(ref findDivingGear);
|
||||
});
|
||||
onCompleted: () => RemoveSubObjective(ref findDivingGear));
|
||||
}
|
||||
else
|
||||
{
|
||||
TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager),
|
||||
onAbandon: () => Abandon = true,
|
||||
onCompleted: () =>
|
||||
{
|
||||
cannotFollow = false;
|
||||
RemoveSubObjective(ref findDivingGear);
|
||||
});
|
||||
onCompleted: () => RemoveSubObjective(ref findDivingGear));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cannotFollow = false;
|
||||
}
|
||||
}
|
||||
if (repeat)
|
||||
{
|
||||
@@ -735,7 +727,6 @@ namespace Barotrauma
|
||||
findDivingGear = null;
|
||||
seekGapsTimer = 0;
|
||||
TargetGap = null;
|
||||
cannotFollow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ namespace Barotrauma
|
||||
if (orderGiver == null) { return null; }
|
||||
newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
|
||||
{
|
||||
CloseEnough = Rand.Range(80, 100),
|
||||
CloseEnough = Rand.Range(80f, 100f),
|
||||
CloseEnoughMultiplier = Math.Min(1 + HumanAIController.CountCrew(c => c.ObjectiveManager.HasOrder<AIObjectiveGoTo>(o => o.Target == orderGiver), onlyBots: true) * Rand.Range(0.8f, 1f), 4),
|
||||
ExtraDistanceOutsideSub = 100,
|
||||
ExtraDistanceWhileSwimming = 100,
|
||||
|
||||
@@ -221,6 +221,9 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public int AssignmentPriority { get; }
|
||||
|
||||
public bool ColoredWhenControllingGiver { get; }
|
||||
public bool DisplayGiverInTooltip { get; }
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Prefabs = new Dictionary<string, Order>();
|
||||
@@ -406,6 +409,8 @@ namespace Barotrauma
|
||||
DrawIconWhenContained = orderElement.GetAttributeBool("displayiconwhencontained", false);
|
||||
AutoDismiss = orderElement.GetAttributeBool("autodismiss", Category == OrderCategory.Movement);
|
||||
AssignmentPriority = Math.Clamp(orderElement.GetAttributeInt("assignmentpriority", 100), 0, 100);
|
||||
ColoredWhenControllingGiver = orderElement.GetAttributeBool("coloredwhencontrollinggiver", false);
|
||||
DisplayGiverInTooltip = orderElement.GetAttributeBool("displaygiverintooltip", false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -441,6 +446,8 @@ namespace Barotrauma
|
||||
Hidden = prefab.Hidden;
|
||||
IgnoreAtOutpost = prefab.IgnoreAtOutpost;
|
||||
AssignmentPriority = prefab.AssignmentPriority;
|
||||
ColoredWhenControllingGiver = prefab.ColoredWhenControllingGiver;
|
||||
DisplayGiverInTooltip = prefab.DisplayGiverInTooltip;
|
||||
|
||||
OrderGiver = orderGiver;
|
||||
TargetEntity = targetEntity;
|
||||
|
||||
@@ -134,6 +134,7 @@ namespace Barotrauma
|
||||
aggregate += Items[i].Commonness;
|
||||
if (aggregate >= r && Items[i].Prefab != null)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("MicroInteraction:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "null") + ":PetProducedItem:" + pet.AiController.Character.SpeciesName + ":" + Items[i].Prefab.Identifier);
|
||||
Entity.Spawner.AddToSpawnQueue(Items[i].Prefab, pet.AiController.Character.WorldPosition);
|
||||
break;
|
||||
}
|
||||
@@ -200,6 +201,8 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("MicroInteraction:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "null") + ":PetSpawned:" + aiController.Character.SpeciesName);
|
||||
}
|
||||
|
||||
public StatusIndicatorType GetCurrentStatusIndicatorType()
|
||||
@@ -210,23 +213,44 @@ namespace Barotrauma
|
||||
return StatusIndicatorType.None;
|
||||
}
|
||||
|
||||
public bool OnEat(IEnumerable<string> tags, float amount)
|
||||
public bool OnEat(Item item)
|
||||
{
|
||||
bool success = OnEat(item.GetTags());
|
||||
if (success)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("MicroInteraction:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "null") + ":PetEat:" + AiController.Character.SpeciesName + ":" + item.prefab.Identifier);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public bool OnEat(Character character)
|
||||
{
|
||||
if (character == null || !character.IsDead) { return false; }
|
||||
bool success = OnEat("dead");
|
||||
if (success)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("MicroInteraction:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "null") + ":PetEat:" + AiController.Character.SpeciesName + ":" + character.SpeciesName);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool OnEat(IEnumerable<string> tags)
|
||||
{
|
||||
foreach (string tag in tags)
|
||||
{
|
||||
if (OnEat(tag, amount)) { return true; }
|
||||
if (OnEat(tag)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnEat(string tag, float amount)
|
||||
private bool OnEat(string tag)
|
||||
{
|
||||
for (int i = 0; i < foods.Count; i++)
|
||||
{
|
||||
if (tag.Equals(foods[i].Tag, System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Hunger += foods[i].Hunger * amount;
|
||||
Happiness += foods[i].Happiness * amount;
|
||||
Hunger += foods[i].Hunger;
|
||||
Happiness += foods[i].Happiness;
|
||||
#if CLIENT
|
||||
AiController.Character.PlaySound(CharacterSound.SoundType.Happy, 0.5f);
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,13 @@ namespace Barotrauma
|
||||
|
||||
public override void CalculateImportanceSpecific()
|
||||
{
|
||||
if (TargetItemComponent is Turret turret && !turret.HasPowerToShoot()) { return; }
|
||||
if (TargetItemComponent is Turret turret && !turret.HasPowerToShoot())
|
||||
{
|
||||
//operate (= recharge the turrets) with low priority if they're out of power
|
||||
//if something else (issues with reactor or the electrical grid) is preventing them from being charged, fixing those issues should take priority
|
||||
Importance = ShipCommandManager.MinimumIssueThreshold * 1.05f;
|
||||
return;
|
||||
}
|
||||
|
||||
targetingImportances.Clear();
|
||||
foreach (Character character in shipCommandManager.EnemyCharacters)
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Barotrauma
|
||||
private const float RamTimerMax = 17.5f;
|
||||
|
||||
public readonly List<ShipIssueWorker> ShipIssueWorkers = new List<ShipIssueWorker>();
|
||||
private const float MinimumIssueThreshold = 10f;
|
||||
public const float MinimumIssueThreshold = 10f;
|
||||
private const float IssueDevotionBuffer = 5f;
|
||||
|
||||
private float decisionTimer = 6f;
|
||||
|
||||
@@ -254,7 +254,7 @@ namespace Barotrauma
|
||||
|
||||
private void SpawnInitialCells()
|
||||
{
|
||||
int brainRoomCells = Rand.Range(MinCellsPerBrainRoom, MaxCellsPerRoom);
|
||||
int brainRoomCells = Rand.Range(MinCellsPerBrainRoom, MaxCellsPerRoom + 1);
|
||||
if (brain.CurrentHull?.WaterPercentage >= MinWaterLevel)
|
||||
{
|
||||
for (int i = 0; i < brainRoomCells; i++)
|
||||
@@ -262,12 +262,12 @@ namespace Barotrauma
|
||||
if (!TrySpawnCell(out _, brain.CurrentHull)) { break; }
|
||||
}
|
||||
}
|
||||
int cellsInside = Rand.Range(MinCellsInside, MaxCellsInside);
|
||||
int cellsInside = Rand.Range(MinCellsInside, MaxCellsInside + 1);
|
||||
for (int i = 0; i < cellsInside; i++)
|
||||
{
|
||||
if (!TrySpawnCell(out _)) { break; }
|
||||
}
|
||||
int cellsOutside = Rand.Range(MinCellsOutside, MaxCellsOutside);
|
||||
int cellsOutside = Rand.Range(MinCellsOutside, MaxCellsOutside + 1);
|
||||
// If we failed to spawn some of the cells in the brainroom/inside, spawn some extra cells outside.
|
||||
cellsOutside = Math.Clamp(cellsOutside + brainRoomCells + cellsInside - protectiveCells.Count, cellsOutside, MaxCellsOutside);
|
||||
for (int i = 0; i < cellsOutside; i++)
|
||||
|
||||
@@ -420,7 +420,7 @@ namespace Barotrauma
|
||||
|
||||
if (Character.AIController is EnemyAIController enemyAi)
|
||||
{
|
||||
enemyAi.PetBehavior?.OnEat("dead", 1.0f);
|
||||
enemyAi.PetBehavior?.OnEat(target);
|
||||
}
|
||||
|
||||
character.SelectedCharacter = null;
|
||||
|
||||
@@ -533,6 +533,8 @@ namespace Barotrauma
|
||||
|
||||
bool onSlope = Math.Abs(movement.X) > 0.01f && Math.Abs(floorNormal.X) > 0.1f && Math.Sign(floorNormal.X) != Math.Sign(movement.X);
|
||||
|
||||
bool movingHorizontally = !MathUtils.NearlyEqual(targetMovement.X, 0.0f);
|
||||
|
||||
if (Stairs != null || onSlope)
|
||||
{
|
||||
torso.PullJointWorldAnchorB = new Vector2(
|
||||
@@ -562,10 +564,8 @@ namespace Barotrauma
|
||||
|
||||
if (!torso.Disabled)
|
||||
{
|
||||
if (TorsoPosition.HasValue)
|
||||
{
|
||||
y += TorsoPosition.Value;
|
||||
}
|
||||
if (TorsoPosition.HasValue) { y += TorsoPosition.Value; }
|
||||
if (Crouching && !movingHorizontally) { y -= HumanCrouchParams.MoveDownAmountWhenStationary; }
|
||||
torso.PullJointWorldAnchorB =
|
||||
MathUtils.SmoothStep(torso.SimPosition,
|
||||
new Vector2(footMid + movement.X * TorsoLeanAmount, y), getUpForce);
|
||||
@@ -574,10 +574,8 @@ namespace Barotrauma
|
||||
if (!head.Disabled)
|
||||
{
|
||||
y = colliderPos.Y + stepLift * CurrentGroundedParams.StepLiftHeadMultiplier;
|
||||
if (HeadPosition.HasValue)
|
||||
{
|
||||
y += HeadPosition.Value;
|
||||
}
|
||||
if (HeadPosition.HasValue) { y += HeadPosition.Value; }
|
||||
if (Crouching && !movingHorizontally) { y -= HumanCrouchParams.MoveDownAmountWhenStationary; }
|
||||
head.PullJointWorldAnchorB =
|
||||
MathUtils.SmoothStep(head.SimPosition,
|
||||
new Vector2(footMid + movement.X * HeadLeanAmount, y), getUpForce * 1.2f);
|
||||
@@ -593,12 +591,15 @@ namespace Barotrauma
|
||||
{
|
||||
float torsoAngle = TorsoAngle.Value;
|
||||
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
||||
if (Crouching && !movingHorizontally) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
|
||||
torsoAngle -= herpesStrength / 150.0f;
|
||||
torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque);
|
||||
}
|
||||
if (HeadAngle.HasValue)
|
||||
{
|
||||
head.body.SmoothRotate(HeadAngle.Value * Dir, CurrentGroundedParams.HeadTorque);
|
||||
float headAngle = HeadAngle.Value;
|
||||
if (Crouching && !movingHorizontally) { headAngle -= HumanCrouchParams.ExtraHeadAngleWhenStationary; }
|
||||
head.body.SmoothRotate(headAngle * Dir, CurrentGroundedParams.HeadTorque);
|
||||
}
|
||||
|
||||
if (!onGround)
|
||||
@@ -616,8 +617,7 @@ namespace Barotrauma
|
||||
|
||||
Vector2 waistPos = waist != null ? waist.SimPosition : torso.SimPosition;
|
||||
|
||||
//moving horizontally
|
||||
if (TargetMovement.X != 0.0f)
|
||||
if (movingHorizontally)
|
||||
{
|
||||
//progress the walking animation
|
||||
WalkPos -= MathHelper.ToRadians(CurrentAnimationParams.CycleSpeed) * walkCycleMultiplier * movement.X;
|
||||
|
||||
@@ -261,9 +261,16 @@ namespace Barotrauma
|
||||
|
||||
public AttackResult LastDamage;
|
||||
|
||||
public Dictionary<ItemPrefab, double> ItemSelectedDurations
|
||||
{
|
||||
get { return itemSelectedDurations; }
|
||||
}
|
||||
private readonly Dictionary<ItemPrefab, double> itemSelectedDurations = new Dictionary<ItemPrefab, double>();
|
||||
private double itemSelectedTime;
|
||||
|
||||
public float InvisibleTimer;
|
||||
|
||||
private CharacterPrefab prefab;
|
||||
private readonly CharacterPrefab prefab;
|
||||
|
||||
public readonly CharacterParams Params;
|
||||
public string SpeciesName => Params?.SpeciesName ?? "null";
|
||||
@@ -700,7 +707,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!CanSpeak || IsUnconscious || Stun > 0.0f || IsDead) { return 100.0f; }
|
||||
if (!CanSpeak || IsUnconscious || IsKnockedDown) { return 100.0f; }
|
||||
return speechImpediment;
|
||||
}
|
||||
set
|
||||
@@ -737,9 +744,7 @@ namespace Barotrauma
|
||||
get => _selectedConstruction;
|
||||
set
|
||||
{
|
||||
#if CLIENT
|
||||
var prevSelectedConstruction = _selectedConstruction;
|
||||
#endif
|
||||
_selectedConstruction = value;
|
||||
#if CLIENT
|
||||
HintManager.OnSetSelectedConstruction(this, prevSelectedConstruction, _selectedConstruction);
|
||||
@@ -755,6 +760,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (prevSelectedConstruction == null && _selectedConstruction != null)
|
||||
{
|
||||
itemSelectedTime = Timing.TotalTime;
|
||||
}
|
||||
else if (prevSelectedConstruction != null && _selectedConstruction == null && itemSelectedTime > 0)
|
||||
{
|
||||
if (!itemSelectedDurations.ContainsKey(prevSelectedConstruction.Prefab))
|
||||
{
|
||||
itemSelectedDurations.Add(prevSelectedConstruction.Prefab, 0);
|
||||
}
|
||||
itemSelectedDurations[prevSelectedConstruction.Prefab] += Timing.TotalTime - itemSelectedTime;
|
||||
itemSelectedTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3950,27 +3968,44 @@ namespace Barotrauma
|
||||
|
||||
AnimController.Frozen = false;
|
||||
|
||||
if (GameAnalyticsManager.SendUserStatistics)
|
||||
{
|
||||
string characterType = "Unknown";
|
||||
|
||||
if (this == Controlled)
|
||||
characterType = "Player";
|
||||
else if (IsRemotePlayer)
|
||||
characterType = "RemotePlayer";
|
||||
else if (AIController is EnemyAIController)
|
||||
characterType = "Enemy";
|
||||
else if (AIController is HumanAIController)
|
||||
characterType = "AICrew";
|
||||
|
||||
string causeOfDeathStr = causeOfDeathAffliction == null ?
|
||||
causeOfDeath.ToString() : causeOfDeathAffliction.Prefab.Name.Replace(" ", "");
|
||||
GameAnalyticsManager.AddDesignEvent("Kill:" + characterType + ":" + SpeciesName + ":" + causeOfDeathStr);
|
||||
}
|
||||
|
||||
CauseOfDeath = new CauseOfDeath(
|
||||
causeOfDeath, causeOfDeathAffliction?.Prefab,
|
||||
causeOfDeathAffliction?.Source ?? LastAttacker, LastDamageSource);
|
||||
causeOfDeathAffliction?.Source, LastDamageSource);
|
||||
|
||||
if (GameAnalyticsManager.SendUserStatistics)
|
||||
{
|
||||
string causeOfDeathStr = causeOfDeathAffliction == null ?
|
||||
causeOfDeath.ToString() : causeOfDeathAffliction.Prefab.Identifier.Replace(" ", "");
|
||||
|
||||
string characterType = GetCharacterType(this);
|
||||
GameAnalyticsManager.AddDesignEvent("Kill:" + characterType + ":" + causeOfDeathStr);
|
||||
if (CauseOfDeath.Killer != null)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("Kill:" + characterType + ":Killer:" + GetCharacterType(CauseOfDeath.Killer));
|
||||
}
|
||||
if (CauseOfDeath.DamageSource != null)
|
||||
{
|
||||
string damageSourceStr = CauseOfDeath.DamageSource.ToString();
|
||||
if (CauseOfDeath.DamageSource is Item damageSourceItem) { damageSourceStr = damageSourceItem.ToString(); }
|
||||
GameAnalyticsManager.AddDesignEvent("Kill:" + characterType + ":DamageSource:" + damageSourceStr);
|
||||
}
|
||||
|
||||
static string GetCharacterType(Character character)
|
||||
{
|
||||
if (character.IsPlayer)
|
||||
return "Player";
|
||||
else if (character.AIController is EnemyAIController)
|
||||
return "Enemy" + character.SpeciesName;
|
||||
else if (character.AIController is HumanAIController && character.TeamID == CharacterTeamType.Team2)
|
||||
return "EnemyHuman";
|
||||
else if (character.Info != null && character.TeamID == CharacterTeamType.Team1)
|
||||
return "AICrew";
|
||||
else if (character.Info != null && character.TeamID == CharacterTeamType.FriendlyNPC)
|
||||
return "FriendlyNPC";
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
OnDeath?.Invoke(this, CauseOfDeath);
|
||||
|
||||
var abilityCharacterKiller = new AbilityCharacterKiller(CauseOfDeath.Killer);
|
||||
@@ -4097,7 +4132,7 @@ namespace Barotrauma
|
||||
info?.Remove();
|
||||
|
||||
#if CLIENT
|
||||
GameMain.GameSession?.CrewManager?.KillCharacter(this);
|
||||
GameMain.GameSession?.CrewManager?.KillCharacter(this, resetCrewListIndex: false);
|
||||
#endif
|
||||
|
||||
CharacterList.Remove(this);
|
||||
@@ -4112,6 +4147,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
itemSelectedDurations.Clear();
|
||||
|
||||
DisposeProjSpecific();
|
||||
|
||||
aiTarget?.Remove();
|
||||
|
||||
@@ -1527,7 +1527,7 @@ namespace Barotrauma
|
||||
orderTargetElement.Add(new XAttribute("hullid", (uint)ot.Hull.ID));
|
||||
position -= ot.Hull.WorldPosition;
|
||||
}
|
||||
orderTargetElement.Add(new XAttribute("position", $"{position.X},{position.Y}"));
|
||||
orderTargetElement.Add(new XAttribute("position", XMLExtensions.Vector2ToString(position)));
|
||||
orderElement.Add(orderTargetElement);
|
||||
break;
|
||||
case Order.OrderTargetType.WallSection when targetAvailableInNextLevel && order.TargetEntity is Structure s && order.WallSectionIndex.HasValue:
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (State != InfectionState.Active && stun)
|
||||
{
|
||||
character.SetStun(Rand.Range(2, 4));
|
||||
character.SetStun(Rand.Range(2f, 3f));
|
||||
}
|
||||
State = InfectionState.Active;
|
||||
ActivateHusk();
|
||||
|
||||
@@ -363,7 +363,9 @@ namespace Barotrauma
|
||||
public readonly string Name, Description;
|
||||
public readonly string TranslationOverride;
|
||||
public readonly bool IsBuff;
|
||||
public readonly bool HealableInMedicalClinic;
|
||||
public readonly float HealCostMultiplier;
|
||||
public readonly int BaseHealCost;
|
||||
|
||||
public readonly string CauseOfDeathDescription, SelfCauseOfDeathDescription;
|
||||
|
||||
@@ -656,7 +658,13 @@ namespace Barotrauma
|
||||
Name = TextManager.Get("AfflictionName." + translationId, true) ?? element.GetAttributeString("name", "");
|
||||
Description = TextManager.Get("AfflictionDescription." + translationId, true) ?? element.GetAttributeString("description", "");
|
||||
IsBuff = element.GetAttributeBool("isbuff", false);
|
||||
|
||||
HealableInMedicalClinic = element.GetAttributeBool("healableinmedicalclinic",
|
||||
!IsBuff &&
|
||||
!AfflictionType.Equals("geneticmaterialbuff", StringComparison.OrdinalIgnoreCase) &&
|
||||
!AfflictionType.Equals("geneticmaterialdebuff", StringComparison.OrdinalIgnoreCase));
|
||||
HealCostMultiplier = element.GetAttributeFloat(nameof(HealCostMultiplier).ToLowerInvariant(), 1f);
|
||||
BaseHealCost = element.GetAttributeInt(nameof(BaseHealCost).ToLowerInvariant(), 0);
|
||||
|
||||
if (element.Attribute("nameidentifier") != null)
|
||||
{
|
||||
|
||||
@@ -764,6 +764,7 @@ namespace Barotrauma
|
||||
if (applyAffliction)
|
||||
{
|
||||
afflictionsCopy.Add(newAffliction);
|
||||
newAffliction.Source ??= attacker;
|
||||
}
|
||||
appliedDamageModifiers.AddRange(tempModifiers);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,15 @@ namespace Barotrauma
|
||||
|
||||
class HumanCrouchParams : HumanGroundedParams
|
||||
{
|
||||
[Serialize(0.0f, true, description: "How much lower the character's head and torso move when stationary."), Editable(MinValueFloat = 0, MaxValueFloat = 2, DecimalCount = 2)]
|
||||
public float MoveDownAmountWhenStationary { get; set; }
|
||||
|
||||
[Serialize(0.0f, true), Editable(-360f, 360f)]
|
||||
public float ExtraHeadAngleWhenStationary { get; set; }
|
||||
|
||||
[Serialize(0.0f, true), Editable(-360f, 360f)]
|
||||
public float ExtraTorsoAngleWhenStationary { get; set; }
|
||||
|
||||
public static HumanCrouchParams GetDefaultAnimParams(Character character) => GetDefaultAnimParams<HumanCrouchParams>(character, AnimationType.Crouch);
|
||||
public static HumanCrouchParams GetAnimParams(Character character, string fileName = null)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,9 @@ namespace Barotrauma.Abilities
|
||||
multiplier = 0 + Character.Info.GetSavedStatValue(StatTypes.None, scalingStatIdentifier);
|
||||
}
|
||||
|
||||
targetCharacter.GiveMoney((int)(multiplier * amount));
|
||||
int totalAmount = (int)(multiplier * amount);
|
||||
targetCharacter.GiveMoney(totalAmount);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(totalAmount, GameAnalyticsManager.MoneySource.Ability, CharacterTalent.Prefab.Identifier);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
|
||||
@@ -16,7 +16,9 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if ((abilityObject as IAbilityCharacter)?.Character is Character character)
|
||||
{
|
||||
Character.GiveMoney((int)(vitalityPercentage * character.MaxVitality));
|
||||
int totalAmount = (int)(vitalityPercentage * character.MaxVitality);
|
||||
Character.GiveMoney(totalAmount);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(totalAmount, GameAnalyticsManager.MoneySource.Ability, CharacterTalent.Prefab.Identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Barotrauma.Abilities
|
||||
if (!enemyCharacter.LockHands) { continue; }
|
||||
if (timesGiven > max) { continue; }
|
||||
Character.GiveMoney(moneyAmount);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(moneyAmount, GameAnalyticsManager.MoneySource.Ability, CharacterTalent.Prefab.Identifier);
|
||||
foreach (Character character in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
character.Info?.GiveExperience(experienceAmount);
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace Barotrauma.Abilities
|
||||
|
||||
private readonly int moneyPerMission;
|
||||
|
||||
private static List<Client> clientsAlreadyUsed = new List<Client>();
|
||||
|
||||
public CharacterAbilityInsurancePolicy(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
moneyPerMission = abilityElement.GetAttributeInt("moneypermission", 0);
|
||||
@@ -23,7 +21,9 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (Character?.Info is CharacterInfo info)
|
||||
{
|
||||
Character.GiveMoney(moneyPerMission * info.MissionsCompletedSinceDeath);
|
||||
int totalAmount = moneyPerMission * info.MissionsCompletedSinceDeath;
|
||||
Character.GiveMoney(totalAmount);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(totalAmount, GameAnalyticsManager.MoneySource.Ability, CharacterTalent.Prefab.Identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1534,6 +1534,7 @@ namespace Barotrauma
|
||||
if (int.TryParse(args[0], out int money))
|
||||
{
|
||||
campaign.Money += money;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Barotrauma
|
||||
if (GameMain.GameSession?.GameMode is CampaignMode campaign)
|
||||
{
|
||||
campaign.Money += Amount;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(Amount, GameAnalyticsManager.MoneySource.Event, ParentEvent.Prefab.Identifier);
|
||||
#if SERVER
|
||||
(campaign as MultiPlayerCampaign).LastUpdateID++;
|
||||
#endif
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace Barotrauma
|
||||
if (spawnPoint is WayPoint wp && wp.CurrentHull != null && wp.CurrentHull.Rect.Width > 100)
|
||||
{
|
||||
spawnPos = new Vector2(
|
||||
MathHelper.Clamp(wp.WorldPosition.X + Rand.Range(-200, 200), wp.CurrentHull.WorldRect.X + 50, wp.CurrentHull.WorldRect.Right - 50),
|
||||
MathHelper.Clamp(wp.WorldPosition.X + Rand.Range(-200, 201), wp.CurrentHull.WorldRect.X + 50, wp.CurrentHull.WorldRect.Right - 50),
|
||||
wp.CurrentHull.WorldRect.Y - wp.CurrentHull.Rect.Height + 16.0f);
|
||||
}
|
||||
var item = new Item(itemPrefab, spawnPos, null);
|
||||
|
||||
@@ -319,6 +319,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Character character in characters)
|
||||
{
|
||||
if (character.Inventory == null) { continue; }
|
||||
foreach (Item item in character.Inventory.AllItemsMod)
|
||||
{
|
||||
//item didn't spawn with the characters -> drop it
|
||||
if (!characterItems.Any(c => c.Value.Contains(item)))
|
||||
{
|
||||
item.Drop(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// characters that survived will take their items with them, in case players tried to be crafty and steal them
|
||||
// this needs to run here in case players abort the mission by going back home
|
||||
// TODO: I think this might feel like a bug.
|
||||
|
||||
@@ -378,7 +378,10 @@ namespace Barotrauma
|
||||
crewCharacters.ForEach(c => c.CheckTalents(AbilityEffectType.OnGainMissionMoney, missionMoneyGainMultiplier));
|
||||
crewCharacters.ForEach(c => missionMoneyGainMultiplier.Value += c.GetStatValue(StatTypes.MissionMoneyGainMultiplier));
|
||||
|
||||
campaign.Money += (int)(reward * missionMoneyGainMultiplier.Value);
|
||||
int totalReward = (int)(reward * missionMoneyGainMultiplier.Value);
|
||||
campaign.Money += totalReward;
|
||||
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(totalReward, GameAnalyticsManager.MoneySource.MissionReward, Prefab.Identifier);
|
||||
|
||||
foreach (Character character in crewCharacters)
|
||||
{
|
||||
|
||||
@@ -328,7 +328,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = new Vector2(1, Rand.Range(-1, 1));
|
||||
dir = new Vector2(1, Rand.Range(-1f, 1f));
|
||||
}
|
||||
Vector2 targetPos = spawnPos.Value + dir * offset;
|
||||
var targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault();
|
||||
@@ -475,6 +475,7 @@ namespace Barotrauma
|
||||
{
|
||||
scatterAmount = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
string seed = Level.Loaded.Seed + i.ToString();
|
||||
@@ -540,6 +541,13 @@ namespace Barotrauma
|
||||
SwarmBehavior.CreateSwarm(monsters.Cast<AICharacter>());
|
||||
DebugConsole.NewMessage($"Spawned: {ToString()}. Strength: {StringFormatter.FormatZeroDecimal(monsters.Sum(m => m.Params.AI.CombatStrength))}.", Color.LightBlue, debugOnly: true);
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent(
|
||||
$"MonsterSpawn:{GameMain.GameSession.GameMode?.Preset?.Identifier ?? "none"}:{Level.Loaded?.LevelData?.Biome?.Identifier ?? "none"}:{SpawnPosType}:{speciesName}",
|
||||
value: Timing.TotalTime - GameMain.GameSession.RoundStartTime);
|
||||
}
|
||||
}, delayBetweenSpawns * i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using System;
|
||||
using Barotrauma.Steam;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static partial class GameAnalyticsManager
|
||||
static partial class GameAnalyticsManager
|
||||
{
|
||||
public enum Consent
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using Barotrauma.IO;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -9,7 +10,7 @@ using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static partial class GameAnalyticsManager
|
||||
static partial class GameAnalyticsManager
|
||||
{
|
||||
public enum ErrorSeverity
|
||||
{
|
||||
@@ -29,6 +30,61 @@ namespace Barotrauma
|
||||
Fail = 3
|
||||
}
|
||||
|
||||
public enum CustomDimensions01
|
||||
{
|
||||
Vanilla,
|
||||
Modded
|
||||
}
|
||||
|
||||
public enum CustomDimensions02
|
||||
{
|
||||
None,
|
||||
Difficulty0to10,
|
||||
Difficulty10to20,
|
||||
Difficulty20to30,
|
||||
Difficulty30to40,
|
||||
Difficulty40to50,
|
||||
Difficulty50to60,
|
||||
Difficulty60to70,
|
||||
Difficulty70to80,
|
||||
Difficulty80to90,
|
||||
Difficulty90to100,
|
||||
}
|
||||
|
||||
public enum ResourceCurrency
|
||||
{
|
||||
Money
|
||||
}
|
||||
|
||||
public enum ResourceFlowType
|
||||
{
|
||||
Undefined = 0,
|
||||
Source = 1,
|
||||
Sink = 2
|
||||
}
|
||||
|
||||
public enum MoneySource
|
||||
{
|
||||
Unknown,
|
||||
MissionReward,
|
||||
Store,
|
||||
Event,
|
||||
Ability,
|
||||
Cheat
|
||||
}
|
||||
|
||||
public enum MoneySink
|
||||
{
|
||||
Unknown,
|
||||
Store,
|
||||
Service,
|
||||
Crew,
|
||||
SubmarineUpgrade,
|
||||
SubmarineWeapon,
|
||||
SubmarinePurchase,
|
||||
SubmarineSwitch
|
||||
}
|
||||
|
||||
private readonly static HashSet<string> sentEventIdentifiers = new HashSet<string>();
|
||||
|
||||
private class Implementation : IDisposable
|
||||
@@ -69,13 +125,29 @@ namespace Barotrauma
|
||||
internal void AddProgressionEvent(ProgressionStatus status, string progression01, string progression02, string progression03)
|
||||
=> addProgressionEvent03(status, progression01, progression02, progression03);
|
||||
|
||||
private readonly Action<ResourceFlowType, string, float, string, string> addResourceEvent;
|
||||
internal void AddResourceEvent(ResourceFlowType flowType, string currency, float amount, string itemType, string itemId)
|
||||
=> addResourceEvent(flowType, currency, amount, itemType, itemId);
|
||||
|
||||
private readonly Action<string> setCustomDimension01;
|
||||
internal void SetCustomDimension01(string dimension01)
|
||||
=> setCustomDimension01(dimension01);
|
||||
|
||||
private readonly Action<string[]> configureAvailableCustomDimensions01;
|
||||
internal void ConfigureAvailableCustomDimensions01(params string[] customDimensions)
|
||||
=> configureAvailableCustomDimensions01(customDimensions);
|
||||
internal void ConfigureAvailableCustomDimensions01(params CustomDimensions01[] customDimensions)
|
||||
=> configureAvailableCustomDimensions01(customDimensions.Select(d => d.ToString()).ToArray());
|
||||
|
||||
private readonly Action<string> setCustomDimension02;
|
||||
internal void SetCustomDimension02(string dimension02)
|
||||
=> setCustomDimension02(dimension02);
|
||||
|
||||
private readonly Action<string[]> configureAvailableCustomDimensions02;
|
||||
internal void ConfigureAvailableCustomDimensions02(params CustomDimensions02[] customDimensions)
|
||||
=> configureAvailableCustomDimensions02(customDimensions.Select(d => d.ToString()).ToArray());
|
||||
|
||||
private readonly Action<string[]> configureAvailableResourceCurrencies;
|
||||
internal void ConfigureAvailableResourceCurrencies(params ResourceCurrency[] customDimensions)
|
||||
=> configureAvailableResourceCurrencies(customDimensions.Select(d => d.ToString()).ToArray());
|
||||
|
||||
private readonly Action<bool> setEnabledInfoLog;
|
||||
internal void SetEnabledInfoLog(bool enabled)
|
||||
@@ -94,6 +166,7 @@ namespace Barotrauma
|
||||
private readonly object?[] args2 = new object?[2];
|
||||
private readonly object?[] args3 = new object?[3];
|
||||
private readonly object?[] args4 = new object?[4];
|
||||
private readonly object?[] args5 = new object?[5];
|
||||
|
||||
private Action Call(MethodInfo methodInfo)
|
||||
=> () => methodInfo?.Invoke(null, null);
|
||||
@@ -131,6 +204,17 @@ namespace Barotrauma
|
||||
args4[3] = arg4;
|
||||
methodInfo.Invoke(null, args4);
|
||||
};
|
||||
|
||||
private Action<T1, T2, T3, T4, T5> Call<T1, T2, T3, T4, T5>(MethodInfo methodInfo)
|
||||
=> (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) =>
|
||||
{
|
||||
args5[0] = arg1;
|
||||
args5[1] = arg2;
|
||||
args5[2] = arg3;
|
||||
args5[3] = arg4;
|
||||
args5[4] = arg5;
|
||||
methodInfo.Invoke(null, args5);
|
||||
};
|
||||
#endregion
|
||||
|
||||
private AssemblyLoadContext? loadContext;
|
||||
@@ -165,9 +249,15 @@ namespace Barotrauma
|
||||
var mainClass = getType(MainClass);
|
||||
var errorSeverityEnumType = getType($"{EnumPrefix}{nameof(ErrorSeverity)}");
|
||||
var progressionStatusEnumType = getType($"{EnumPrefix}{nameof(ProgressionStatus)}");
|
||||
var resourceFlowTypeEnumType = getType($"{EnumPrefix}{nameof(ResourceFlowType)}");
|
||||
|
||||
MethodInfo getMethod(string name, Type[] types)
|
||||
{
|
||||
foreach (var me in mainClass.GetMethods())
|
||||
{
|
||||
var aksjdnakjsdnf = me;
|
||||
}
|
||||
|
||||
return mainClass?.GetMethod(name, BindingFlags.Public | BindingFlags.Static, binder: null, types: types, modifiers: null)
|
||||
?? throw new Exception($"Could not find method \"{name}\" with types {string.Join(',', types.Select(t => t.Name))}");
|
||||
}
|
||||
@@ -190,10 +280,20 @@ namespace Barotrauma
|
||||
new Type[] { progressionStatusEnumType, typeof(string), typeof(string) }));
|
||||
addProgressionEvent03 = Call<ProgressionStatus, string, string, string>(getMethod(nameof(AddProgressionEvent),
|
||||
new Type[] { progressionStatusEnumType, typeof(string), typeof(string), typeof(string) }));
|
||||
|
||||
setCustomDimension01 = Call<string>(getMethod(nameof(SetCustomDimension01),
|
||||
new Type[] { typeof(string) }));
|
||||
configureAvailableCustomDimensions01 = Call<string[]>(getMethod(nameof(ConfigureAvailableCustomDimensions01),
|
||||
new Type[] { typeof(string[]) }));
|
||||
setCustomDimension02 = Call<string>(getMethod(nameof(SetCustomDimension02),
|
||||
new Type[] { typeof(string) }));
|
||||
configureAvailableCustomDimensions02 = Call<string[]>(getMethod(nameof(ConfigureAvailableCustomDimensions02),
|
||||
new Type[] { typeof(string[]) }));
|
||||
|
||||
configureAvailableResourceCurrencies = Call<string[]>(getMethod(nameof(ConfigureAvailableResourceCurrencies),
|
||||
new Type[] { typeof(string[]) }));
|
||||
addResourceEvent = Call<ResourceFlowType, string, float, string, string>(getMethod(nameof(AddResourceEvent),
|
||||
new Type[] { resourceFlowTypeEnumType, typeof(string), typeof(float), typeof(string), typeof(string) }));
|
||||
setEnabledInfoLog = Call<bool>(getMethod(nameof(SetEnabledInfoLog),
|
||||
new Type[] { typeof(bool) }));
|
||||
|
||||
@@ -204,8 +304,7 @@ namespace Barotrauma
|
||||
private void OnQuit()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
{
|
||||
if (assembly != null) { onQuit?.Invoke(); }
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -298,10 +397,40 @@ namespace Barotrauma
|
||||
loadedImplementation?.AddProgressionEvent(progressionStatus, progression01, progression02, progression03);
|
||||
}
|
||||
|
||||
public static void SetCustomDimension01(string dimension)
|
||||
public static void SetCustomDimension01(CustomDimensions01 dimension)
|
||||
{
|
||||
if (!SendUserStatistics) { return; }
|
||||
loadedImplementation?.SetCustomDimension01(dimension);
|
||||
loadedImplementation?.SetCustomDimension01(dimension.ToString());
|
||||
}
|
||||
|
||||
public static void SetCurrentLevel(LevelData levelData)
|
||||
{
|
||||
if (!SendUserStatistics) { return; }
|
||||
|
||||
CustomDimensions02 customDimension = CustomDimensions02.None;
|
||||
if (levelData != null)
|
||||
{
|
||||
float levelDifficulty = levelData.Difficulty;
|
||||
customDimension = (CustomDimensions02)MathHelper.Clamp((int)(levelDifficulty / 10) + 1, 0, Enum.GetValues(typeof(CustomDimensions02)).Length - 1);
|
||||
}
|
||||
|
||||
loadedImplementation?.SetCustomDimension02(customDimension.ToString());
|
||||
}
|
||||
|
||||
public static void AddMoneyGainedEvent(int amount, MoneySource moneySource, string eventId)
|
||||
{
|
||||
AddResourceEvent(ResourceFlowType.Source, ResourceCurrency.Money, amount, moneySource.ToString(), eventId);
|
||||
}
|
||||
|
||||
public static void AddMoneySpentEvent(int amount, MoneySink moneySink, string eventId)
|
||||
{
|
||||
AddResourceEvent(ResourceFlowType.Sink, ResourceCurrency.Money, amount, moneySink.ToString(), eventId);
|
||||
}
|
||||
|
||||
private static void AddResourceEvent(ResourceFlowType flowType, ResourceCurrency currency, float amount, string eventType, string eventId)
|
||||
{
|
||||
if (!SendUserStatistics) { return; }
|
||||
loadedImplementation?.AddResourceEvent(flowType, currency.ToString(), amount, eventType, eventId);
|
||||
}
|
||||
|
||||
private static void Init()
|
||||
@@ -359,7 +488,8 @@ namespace Barotrauma
|
||||
+ exeName + ":"
|
||||
+ AssemblyInfo.GitRevision + ":"
|
||||
+ buildConfiguration);
|
||||
loadedImplementation?.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor");
|
||||
loadedImplementation?.ConfigureAvailableCustomDimensions01(Enum.GetValues(typeof(CustomDimensions01)).Cast<CustomDimensions01>().ToArray());
|
||||
loadedImplementation?.ConfigureAvailableResourceCurrencies(Enum.GetValues(typeof(ResourceCurrency)).Cast<ResourceCurrency>().ToArray());
|
||||
|
||||
InitKeys();
|
||||
|
||||
@@ -380,15 +510,16 @@ namespace Barotrauma
|
||||
var allPackages = GameMain.Config?.AllEnabledPackages.ToList();
|
||||
if (allPackages?.Count > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("ContentPackage: ");
|
||||
int i = 0;
|
||||
List<string> packageNames = new List<string>();
|
||||
foreach (ContentPackage cp in allPackages)
|
||||
{
|
||||
string trimmedName = cp.Name.Replace(":", "").Replace(" ", "");
|
||||
sb.Append(trimmedName.Substring(0, Math.Min(32, trimmedName.Length)));
|
||||
if (i < allPackages.Count - 1) { sb.Append(" "); }
|
||||
string sanitizedName = cp.Name.Replace(":", "").Replace(" ", "");
|
||||
sanitizedName = sanitizedName.Substring(0, Math.Min(32, sanitizedName.Length));
|
||||
packageNames.Add(sanitizedName);
|
||||
loadedImplementation?.AddDesignEvent("ContentPackage:" + sanitizedName);
|
||||
}
|
||||
loadedImplementation?.AddDesignEvent(sb.ToString());
|
||||
packageNames.Sort();
|
||||
loadedImplementation?.AddDesignEvent("AllContentPackages:" + string.Join(", ", packageNames));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ namespace Barotrauma
|
||||
// Exchange money
|
||||
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
||||
campaign.Money -= itemValue;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemValue, GameAnalyticsManager.MoneySink.Store, item.ItemPrefab.Identifier);
|
||||
Location.StoreCurrentBalance += itemValue;
|
||||
|
||||
if (removeFromCrate)
|
||||
@@ -291,7 +292,7 @@ namespace Barotrauma
|
||||
float floorPos = hull.Rect.Y - hull.Rect.Height;
|
||||
|
||||
Vector2 position = new Vector2(
|
||||
hull.Rect.Width > 40 ? Rand.Range(hull.Rect.X + 20, hull.Rect.Right - 20) : hull.Rect.Center.X,
|
||||
hull.Rect.Width > 40 ? Rand.Range(hull.Rect.X + 20f, hull.Rect.Right - 20f) : hull.Rect.Center.X,
|
||||
floorPos);
|
||||
|
||||
//check where the actual floor structure is in case the bottom of the hull extends below it
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace Barotrauma
|
||||
{
|
||||
IsSinglePlayer = isSinglePlayer;
|
||||
conversationTimer = 5.0f;
|
||||
|
||||
InitProjectSpecific();
|
||||
}
|
||||
|
||||
@@ -100,10 +99,10 @@ namespace Barotrauma
|
||||
foreach (XElement characterElement in element.Elements())
|
||||
{
|
||||
if (!characterElement.Name.ToString().Equals("character", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
CharacterInfo characterInfo = new CharacterInfo(characterElement);
|
||||
#if CLIENT
|
||||
if (characterElement.GetAttributeBool("lastcontrolled", false)) { characterInfo.LastControlled = true; }
|
||||
characterInfo.CrewListIndex = characterElement.GetAttributeInt("crewlistindex", -1);
|
||||
#endif
|
||||
characterInfos.Add(characterInfo);
|
||||
foreach (XElement subElement in characterElement.Elements())
|
||||
@@ -133,7 +132,7 @@ namespace Barotrauma
|
||||
characterInfos.Remove(characterInfo);
|
||||
}
|
||||
|
||||
public void AddCharacter(Character character)
|
||||
public void AddCharacter(Character character, bool sortCrewList = true)
|
||||
{
|
||||
if (character.Removed)
|
||||
{
|
||||
@@ -155,7 +154,11 @@ namespace Barotrauma
|
||||
characterInfos.Add(character.Info);
|
||||
}
|
||||
#if CLIENT
|
||||
AddCharacterToCrewList(character);
|
||||
var characterComponent = AddCharacterToCrewList(character);
|
||||
if (sortCrewList)
|
||||
{
|
||||
SortCrewList();
|
||||
}
|
||||
if (character.CurrentOrders != null)
|
||||
{
|
||||
foreach (var order in character.CurrentOrders)
|
||||
@@ -254,12 +257,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
AddCharacter(character);
|
||||
AddCharacter(character, sortCrewList: false);
|
||||
#if CLIENT
|
||||
if (IsSinglePlayer && (Character.Controlled == null || character.Info.LastControlled)) { Character.Controlled = character; }
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (IsSinglePlayer) { SortCrewList(); }
|
||||
#endif
|
||||
|
||||
//longer delay in multiplayer to prevent the server from triggering NPC conversations while the players are still loading the round
|
||||
conversationTimer = IsSinglePlayer ? Rand.Range(5.0f, 10.0f) : Rand.Range(45.0f, 60.0f);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user