Build 0.18.7.0

This commit is contained in:
Markus Isberg
2022-06-08 21:52:38 +09:00
parent 5a10b444ee
commit 4f5a3bf8b9
56 changed files with 401 additions and 245 deletions

View File

@@ -3,7 +3,6 @@ using Barotrauma.Items.Components;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@@ -287,6 +287,11 @@ namespace Barotrauma
InputBox.OnDeselected += (gui, Keys) =>
{
ChatManager.Clear();
if (GUIFrame.IsParentOf(GUI.MouseOn))
{
CloseAfterMessageSent = false;
return;
}
ChatMessage.GetChatMessageCommand(InputBox.Text, out var message);
if (string.IsNullOrEmpty(message))
{

View File

@@ -15,7 +15,7 @@ namespace Barotrauma
get { return inventoryTopY; }
set
{
if (value == inventoryTopY) return;
if (value == inventoryTopY) { return; }
inventoryTopY = value;
CreateAreas();
}
@@ -91,8 +91,6 @@ namespace Barotrauma
if (GameMain.Instance != null)
{
GameMain.Instance.ResolutionChanged += CreateAreas;
#warning TODO: reimplement
//GameSettings.CurrentConfig.OnHUDScaleChanged += CreateAreas;
CreateAreas();
CharacterInfo.Init();
}

View File

@@ -1559,10 +1559,10 @@ namespace Barotrauma
RichString missionReputationString = RichString.Rich(reputationText, wrapMissionText(GUIStyle.Font));
RichString missionDescriptionString = RichString.Rich(descriptionText, wrapMissionText(GUIStyle.Font));
Vector2 missionNameSize = GUIStyle.LargeFont.MeasureString(missionNameString);
Vector2 missionDescriptionSize = GUIStyle.Font.MeasureString(missionDescriptionString);
Vector2 missionRewardSize = GUIStyle.Font.MeasureString(missionRewardString);
Vector2 missionReputationSize = GUIStyle.Font.MeasureString(missionReputationString);
Vector2 missionNameSize = GUIStyle.LargeFont.MeasureString(missionNameString.SanitizedValue);
Vector2 missionDescriptionSize = GUIStyle.Font.MeasureString(missionDescriptionString.SanitizedValue);
Vector2 missionRewardSize = GUIStyle.Font.MeasureString(missionRewardString.SanitizedValue);
Vector2 missionReputationSize = GUIStyle.Font.MeasureString(missionReputationString.SanitizedValue);
float ySize = missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y + missionReputationSize.Y + missionTextGroup.AbsoluteSpacing * 4;
bool displayDifficulty = mission.Difficulty.HasValue;

View File

@@ -102,29 +102,11 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Watchman");
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
var revolver = FindOrGiveItem(captain, "revolver".ToIdentifier());
revolver.Unequip(captain);
captain.Inventory.RemoveItem(revolver);
var captainscap =
captain.Inventory.FindItemByIdentifier("captainscap1".ToIdentifier()) ??
captain.Inventory.FindItemByIdentifier("captainscap2".ToIdentifier()) ??
captain.Inventory.FindItemByIdentifier("captainscap3".ToIdentifier());
if (captainscap != null)
foreach (Item item in captain.Inventory.AllItemsMod)
{
captainscap.Unequip(captain);
captain.Inventory.RemoveItem(captainscap);
}
var captainsuniform =
captain.Inventory.FindItemByIdentifier("captainsuniform1".ToIdentifier()) ??
captain.Inventory.FindItemByIdentifier("captainsuniform2".ToIdentifier()) ??
captain.Inventory.FindItemByIdentifier("captainsuniform3".ToIdentifier());
if (captainsuniform != null)
{
captainsuniform.Unequip(captain);
captain.Inventory.RemoveItem(captainsuniform);
if (item.HasTag("identitycard") || item.HasTag("headset")) { continue; }
item.Unequip(captain);
captain.Inventory.RemoveItem(item);
}
var steerOrder = OrderPrefab.Prefabs["steer"];

View File

@@ -105,21 +105,12 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
doctor = Character.Controlled;
var bandages = FindOrGiveItem(doctor, "antibleeding1".ToIdentifier());
bandages.Unequip(doctor);
doctor.Inventory.RemoveItem(bandages);
var syringegun = FindOrGiveItem(doctor, "syringegun".ToIdentifier());
syringegun.Unequip(doctor);
doctor.Inventory.RemoveItem(syringegun);
var antibiotics = FindOrGiveItem(doctor, "antibiotics".ToIdentifier());
antibiotics.Unequip(doctor);
doctor.Inventory.RemoveItem(antibiotics);
var morphine = FindOrGiveItem(doctor, "antidama1".ToIdentifier());
morphine.Unequip(doctor);
doctor.Inventory.RemoveItem(morphine);
foreach (Item item in doctor.Inventory.AllItemsMod)
{
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; }
item.Unequip(doctor);
doctor.Inventory.RemoveItem(item);
}
doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent<ItemContainer>();
doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent<ItemContainer>();

View File

@@ -131,9 +131,12 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
engineer = Character.Controlled;
var toolbelt = FindOrGiveItem(engineer, "toolbelt".ToIdentifier());
toolbelt.Unequip(engineer);
engineer.Inventory.RemoveItem(toolbelt);
foreach (Item item in engineer.Inventory.AllItemsMod)
{
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; }
item.Unequip(engineer);
engineer.Inventory.RemoveItem(item);
}
var repairOrder = OrderPrefab.Prefabs["repairsystems"];
engineer_repairIcon = repairOrder.SymbolSprite;

View File

@@ -160,13 +160,12 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
mechanic = Character.Controlled;
var toolbelt = FindOrGiveItem(mechanic, "toolbelt".ToIdentifier());
toolbelt.Unequip(mechanic);
mechanic.Inventory.RemoveItem(toolbelt);
var crowbar = FindOrGiveItem(mechanic, "crowbar".ToIdentifier());
crowbar.Unequip(mechanic);
mechanic.Inventory.RemoveItem(crowbar);
foreach (Item item in mechanic.Inventory.AllItemsMod)
{
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; }
item.Unequip(mechanic);
mechanic.Inventory.RemoveItem(item);
}
var repairOrder = OrderPrefab.Prefabs["repairsystems"];
mechanic_repairIcon = repairOrder.SymbolSprite;
@@ -297,7 +296,10 @@ namespace Barotrauma.Tutorials
public override void Update(float deltaTime)
{
mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f);
if (mechanic_brokenhull_1 != null)
{
mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f);
}
base.Update(deltaTime);
}
@@ -413,7 +415,7 @@ namespace Barotrauma.Tutorials
}
} while (mechanic_workingPump.FlowPercentage >= 0 || !mechanic_workingPump.IsActive); // Highlight until draining
SetHighlight(mechanic_workingPump.Item, false);
do { yield return null; } while (mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
do { yield return null; } while (mechanic_brokenhull_1 != null && mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained
RemoveCompletedObjective(3);
GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective3");

View File

@@ -141,36 +141,12 @@ namespace Barotrauma.Tutorials
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
officer = Character.Controlled;
var handcuffs = FindOrGiveItem(officer, "handcuffs".ToIdentifier());
handcuffs.Unequip(officer);
officer.Inventory.RemoveItem(handcuffs);
var stunbaton = FindOrGiveItem(officer, "stunbaton".ToIdentifier());
stunbaton.Unequip(officer);
officer.Inventory.RemoveItem(stunbaton);
var smg = FindOrGiveItem(officer, "smg".ToIdentifier());
smg.Unequip(officer);
officer.Inventory.RemoveItem(smg);
var divingknife = FindOrGiveItem(officer, "divingknife".ToIdentifier());
divingknife.Unequip(officer);
officer.Inventory.RemoveItem(divingknife);
var steroids = FindOrGiveItem(officer, "steroids".ToIdentifier());
steroids.Unequip(officer);
officer.Inventory.RemoveItem(steroids);
var ballistichelmet =
officer.Inventory.FindItemByIdentifier("ballistichelmet1".ToIdentifier()) ??
officer.Inventory.FindItemByIdentifier("ballistichelmet2".ToIdentifier()) ??
FindOrGiveItem(officer, "ballistichelmet3".ToIdentifier());
ballistichelmet.Unequip(officer);
officer.Inventory.RemoveItem(ballistichelmet);
var bodyarmor = FindOrGiveItem(officer, "bodyarmor".ToIdentifier());
bodyarmor.Unequip(officer);
officer.Inventory.RemoveItem(bodyarmor);
foreach (Item item in officer.Inventory.AllItemsMod)
{
if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; }
item.Unequip(officer);
officer.Inventory.RemoveItem(item);
}
var gunOrder = OrderPrefab.Prefabs["operateweapons"];
officer_gunIcon = gunOrder.SymbolSprite;

View File

@@ -28,7 +28,7 @@ namespace Barotrauma
UserListData = "ReadyUserList",
ReadySpriteData = "ReadySprite";
private int lastSecond;
private int lastSecond = 1;
private GUIMessageBox? msgBox;
private GUIMessageBox? resultsBox;
@@ -44,7 +44,7 @@ namespace Barotrauma
msgBox = new GUIMessageBox(readyCheckHeader, readyCheckBody(author), new[] { yesButton, noButton }, relativeSize, minSize, type: GUIMessageBox.Type.Vote) { UserData = PromptData, Draggable = true };
GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.125f), msgBox.Content.RectTransform), childAnchor: Anchor.Center);
new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), time / endTime, GUIStyle.Orange) { UserData = TimerData };
new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), 0.0f, GUIStyle.Orange) { UserData = TimerData };
// Yes
msgBox.Buttons[0].OnClicked = delegate
@@ -116,17 +116,18 @@ namespace Barotrauma
private void UpdateBar()
{
double elapsedTime = (DateTime.Now - startTime).TotalSeconds;
if (msgBox != null && !msgBox.Closed && GUIMessageBox.MessageBoxes.Contains(msgBox))
{
if (msgBox.FindChild(TimerData, true) is GUIProgressBar bar)
{
bar.BarSize = time / endTime;
bar.BarSize = (float)(elapsedTime / (endTime - startTime).TotalSeconds);
}
}
// play click sound after a second has passed
int second = (int) Math.Ceiling(time);
if (second < lastSecond)
int second = (int)Math.Ceiling(elapsedTime);
if (second > lastSecond)
{
if (msgBox != null && !msgBox.Closed)
{
@@ -156,7 +157,8 @@ namespace Barotrauma
bool isOwn = false;
byte authorId = 0;
float duration = inc.ReadSingle();
long startTime = inc.ReadInt64();
long endTime = inc.ReadInt64();
string author = inc.ReadString();
bool hasAuthor = inc.ReadBoolean();
@@ -173,7 +175,9 @@ namespace Barotrauma
clients.Add(inc.ReadByte());
}
ReadyCheck rCheck = new ReadyCheck(clients, duration);
ReadyCheck rCheck = new ReadyCheck(clients,
DateTimeOffset.FromUnixTimeSeconds(startTime).LocalDateTime,
DateTimeOffset.FromUnixTimeSeconds(endTime).LocalDateTime);
crewManager.ActiveReadyCheck = rCheck;
if (isOwn)
@@ -192,12 +196,10 @@ namespace Barotrauma
}
break;
case ReadyCheckState.Update:
float time = inc.ReadSingle();
ReadyStatus newState = (ReadyStatus) inc.ReadByte();
byte targetId = inc.ReadByte();
if (crewManager.ActiveReadyCheck != null)
{
crewManager.ActiveReadyCheck.time = time;
crewManager.ActiveReadyCheck?.UpdateState(targetId, newState);
}
break;

View File

@@ -222,7 +222,8 @@ namespace Barotrauma.Items.Components
if (brokenSprite != null && item.Health < item.MaxCondition)
{
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.MaxCondition) : Vector2.One;
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.MaxCondition) : Vector2.One;
if (IsHorizontal) { scale.X = 1; } else { scale.Y = 1; }
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
spriteBatch.Draw(brokenSprite.Texture, pos,
getSourceRect(brokenSprite, openState, IsHorizontal),

View File

@@ -405,7 +405,7 @@ namespace Barotrauma.Items.Components
float newVolume;
try
{
newVolume = property.GetFloatValue(this);
newVolume = Math.Min(property.GetFloatValue(this), 1.0f);
}
catch
{

View File

@@ -58,6 +58,8 @@ namespace Barotrauma.Items.Components
return true;
}
};
layoutGroup.Recalculate();
}
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox

View File

@@ -33,7 +33,7 @@ namespace Barotrauma
DrawArrow(FlowTargetHull, IsHorizontal ? rect.Height: rect.Width, Math.Abs(lerpedFlowForce.Length()), Color.Red * 0.3f);
}
if (outsideCollisionBlocker.Enabled && Submarine != null)
if (Submarine != null && outsideCollisionBlocker != null && outsideCollisionBlocker.Enabled)
{
var edgeShape = outsideCollisionBlocker.FixtureList[0].Shape as FarseerPhysics.Collision.Shapes.EdgeShape;
Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + Submarine.Position;

View File

@@ -8,7 +8,7 @@ namespace Barotrauma
partial class SubmarineInfo : IDisposable
{
public Sprite PreviewImage;
partial void InitProjectSpecific()
{
string previewImageData = SubmarineElement.GetAttributeString("previewimage", "");

View File

@@ -1200,7 +1200,14 @@ namespace Barotrauma.Networking
new LocalizedString[] { TextManager.Get("Cancel") });
reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; };
connected = false;
var prevContentPackages = clientPeer.ServerContentPackages;
ConnectToServer(serverEndpoint, serverName);
if (clientPeer != null)
{
//restore the previous list of content packages so we can reconnect immediately without having to recheck that the packages match
clientPeer.ServerContentPackages = prevContentPackages;
}
}
else
{

View File

@@ -9,6 +9,7 @@ namespace Barotrauma.Networking
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
msg.Write(NetStateID);
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
msg.WriteRangedInteger((int)ChatMode.None, 0, Enum.GetValues(typeof(ChatMode)).Length - 1);
WriteOrder(msg);
}
}

View File

@@ -50,7 +50,7 @@ namespace Barotrauma.Networking
}
}
public ImmutableArray<ServerContentPackage> ServerContentPackages { get; private set; } =
public ImmutableArray<ServerContentPackage> ServerContentPackages { get; set; } =
ImmutableArray<ServerContentPackage>.Empty;
public delegate void MessageCallback(IReadMessage message);

View File

@@ -117,8 +117,6 @@ namespace Barotrauma.Networking
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
//Console.WriteLine(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte);
if (packetHeader.IsConnectionInitializationStep() && initializationStep != ConnectionInitialization.Success)
{
ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));

View File

@@ -110,7 +110,7 @@ namespace Barotrauma
public SettingValue<GameDifficulty> Difficulty;
public SettingValue<Identifier> StartItemSet;
public CampaignSettings CreateSettings()
public readonly CampaignSettings CreateSettings()
{
return new CampaignSettings(element: null)
{

View File

@@ -210,8 +210,17 @@ namespace Barotrauma
{
CreateCustomizeWindow(CurrentSettings, settings =>
{
CampaignSettings prevSettings = CurrentSettings;
CurrentSettings = settings;
UpdateSubList(SubmarineInfo.SavedSubmarines);
if (prevSettings.InitialMoney != settings.InitialMoney)
{
object selectedData = subList.SelectedData;
UpdateSubList(SubmarineInfo.SavedSubmarines);
if (selectedData is SubmarineInfo selectedSub && selectedSub.Price <= CurrentSettings.InitialMoney)
{
subList.Select(selectedData);
}
}
});
return true;
}
@@ -519,7 +528,7 @@ namespace Barotrauma
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList();
}
subsToShow.Sort((s1, s2) =>
subsToShow.Sort((s1, s2) =>
{
int p1 = s1.Price > CurrentSettings.InitialMoney ? 10 : 0;
int p2 = s2.Price > CurrentSettings.InitialMoney ? 10 : 0;
@@ -537,7 +546,7 @@ namespace Barotrauma
ToolTip = sub.Description,
UserData = sub
};
if (!sub.RequiredContentPackagesInstalled)
{
textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f);

View File

@@ -513,18 +513,18 @@ namespace Barotrauma
var moduleLabel = new GUITextBlock(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(70 * GUI.Scale))), TextManager.Get("submarinetype.outpostmodules"), font: GUIStyle.SubHeadingFont);
outpostParamsEditor.AddCustomContent(moduleLabel, 100);
foreach (KeyValuePair<Identifier, int> moduleCount in outpostGenerationParams.ModuleCounts)
foreach (var moduleCount in outpostGenerationParams.ModuleCounts)
{
var moduleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(25 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Key.Value), textAlignment: Alignment.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Identifier.Value), textAlignment: Alignment.CenterLeft);
new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), NumberType.Int)
{
MinValueInt = 0,
MaxValueInt = 100,
IntValue = moduleCount.Value,
IntValue = moduleCount.Count,
OnValueChanged = (numInput) =>
{
outpostGenerationParams.SetModuleCount(moduleCount.Key, numInput.IntValue);
outpostGenerationParams.SetModuleCount(moduleCount.Identifier, numInput.IntValue);
if (numInput.IntValue == 0)
{
outpostParamsList.Select(outpostParamsList.SelectedData);
@@ -540,7 +540,7 @@ namespace Barotrauma
var addModuleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(40 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.Center);
HashSet<Identifier> availableFlags = new HashSet<Identifier>();
foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); }
foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); }
foreach (var sub in SubmarineInfo.SavedSubmarines)
{
if (sub.OutpostModuleInfo == null) { continue; }
@@ -551,7 +551,7 @@ namespace Barotrauma
text: TextManager.Get("leveleditor.addmoduletype"));
foreach (Identifier flag in availableFlags)
{
if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Key == flag)) { continue; }
if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Identifier == flag)) { continue; }
moduleTypeDropDown.AddItem(TextManager.Capitalize(flag.Value), flag);
}
moduleTypeDropDown.OnSelected += (_, userdata) =>

View File

@@ -1549,6 +1549,11 @@ namespace Barotrauma
MapEntity.DeselectAll();
ClearUndoBuffer();
GameMain.DebugDraw = false;
GameMain.LightManager.LightingEnabled = true;
Hull.EditWater = false;
Hull.EditFire = false;
SetMode(Mode.Default);
SoundPlayer.OverrideMusicType = Identifier.Empty;
@@ -1586,7 +1591,7 @@ namespace Barotrauma
private void CreateDummyCharacter()
{
if (dummyCharacter != null) RemoveDummyCharacter();
if (dummyCharacter != null) { RemoveDummyCharacter(); }
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
dummyCharacter.Info.Name = "Galldren";
@@ -1876,21 +1881,15 @@ namespace Barotrauma
&& MainSub.Info.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
prevSavePath = MainSub.Info.FilePath.CleanUpPath();
string prevDir = Path.GetDirectoryName(MainSub.Info.FilePath).CleanUpPath();
ModProject modProject = new ModProject { Name = name };
string fileListPath = null;
ContentPackage contentPackage = GetLocalPackageThatOwnsSub(MainSub.Info);
if (contentPackage != null)
if (contentPackage == null)
{
modProject = new ModProject(contentPackage);
fileListPath = contentPackage.Path;
packageToSaveTo = contentPackage;
throw new InvalidOperationException($"Tried to overwrite a submarine ({name}) that's not in a local package!");
}
savePath = Path.Combine(prevDir, savePath).CleanUpPath();
addSubAndSaveModProject(modProject, savePath, fileListPath ?? Path.Combine(Path.GetDirectoryName(savePath), ContentPackage.FileListFileName));
ModProject modProject = new ModProject(contentPackage);
packageToSaveTo = contentPackage;
savePath = prevSavePath;
addSubAndSaveModProject(modProject, savePath, contentPackage.Path);
}
else
{
@@ -2074,8 +2073,8 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), outpostModuleGroup.RectTransform), TextManager.Get("outpostmoduletype"), textAlignment: Alignment.CenterLeft);
HashSet<Identifier> availableFlags = new HashSet<Identifier>();
foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); }
foreach (Identifier flag in RuinGeneration.RuinGenerationParams.RuinParams.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); }
foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); }
foreach (Identifier flag in RuinGeneration.RuinGenerationParams.RuinParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); }
foreach (var sub in SubmarineInfo.SavedSubmarines)
{
if (sub.OutpostModuleInfo == null) { continue; }
@@ -2551,11 +2550,9 @@ namespace Barotrauma
{
MainSub.Info.BeaconStationInfo ??= new BeaconStationInfo(MainSub.Info);
}
previewImageButtonHolder.Children.ForEach(c => c.Enabled = type != SubmarineType.OutpostModule);
previewImageButtonHolder.Children.ForEach(c => c.Enabled = MainSub.Info.AllowPreviewImage);
outpostSettingsContainer.Visible = type == SubmarineType.OutpostModule;
beaconSettingsContainer.Visible = type == SubmarineType.BeaconStation;
subSettingsContainer.Visible = type == SubmarineType.Player;
return true;
};
@@ -2572,6 +2569,7 @@ namespace Barotrauma
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), previewImageButtonHolder.RectTransform), TextManager.Get("SubPreviewImageCreate"), style: "GUIButtonSmall")
{
Enabled = MainSub?.Info.AllowPreviewImage ?? false,
OnClicked = (btn, userdata) =>
{
using (System.IO.MemoryStream imgStream = new System.IO.MemoryStream())
@@ -2589,6 +2587,7 @@ namespace Barotrauma
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), previewImageButtonHolder.RectTransform), TextManager.Get("SubPreviewImageBrowse"), style: "GUIButtonSmall")
{
Enabled = MainSub?.Info.AllowPreviewImage ?? false,
OnClicked = (btn, userdata) =>
{
FileSelection.OnFileSelected = (file) =>

View File

@@ -220,7 +220,7 @@ namespace Barotrauma
};
}
private string Percentage(float v) => $"{Round(v * 100)}%";
private string Percentage(float v) => TextManager.GetWithVariable("percentageformat", "[value]", Round(v * 100).ToString()).Value;
private int Round(float v) => (int)MathF.Round(v);
@@ -647,6 +647,8 @@ namespace Barotrauma
{
unsavedConfig.InventoryKeyMap = GameSettings.Config.InventoryKeyMapping.GetDefault();
unsavedConfig.KeyMap = GameSettings.Config.KeyMapping.GetDefault();
Create(mainFrame.Parent.RectTransform);
Instance?.SelectTab(Tab.Controls);
return true;
}
};

View File

@@ -253,12 +253,12 @@ namespace Barotrauma
if (flipHorizontal)
{
float diff = targetSize.X % (sourceRect.Width * scale.X);
flippedDrawOffset.X = (int)((sourceRect.Width * scale.X - diff) / scale.X);
flippedDrawOffset.X = (int)MathF.Round((sourceRect.Width * scale.X - diff) / scale.X);
}
if (flipVertical)
{
float diff = targetSize.Y % (sourceRect.Height * scale.Y);
flippedDrawOffset.Y = (int)((sourceRect.Height * scale.Y - diff) / scale.Y);
flippedDrawOffset.Y = (int)MathF.Round((sourceRect.Height * scale.Y - diff) / scale.Y);
}
drawOffset += flippedDrawOffset;

View File

@@ -562,10 +562,10 @@ namespace Barotrauma.Steam
= (parentList == enabledRegularModsList, parentList.AllSelected.Count > 1);
Identifier swapLabel = (labelConditions switch
{
(true, true) => "EnableSelectedWorkshopMods",
(true, false) => "EnableWorkshopMod",
(false, true) => "DisableSelectedWorkshopMods",
(false, false) => "DisableWorkshopMod"
(false, true) => "EnableSelectedWorkshopMods",
(false, false) => "EnableWorkshopMod",
(true, true) => "DisableSelectedWorkshopMods",
(true, false) => "DisableWorkshopMod"
}).ToIdentifier();
contextMenuOptions.Add(new ContextMenuOption(swapLabel,

View File

@@ -595,6 +595,12 @@ namespace Barotrauma.Steam
{
ContentPackageManager.WorkshopPackages.Refresh();
ContentPackageManager.EnabledPackages.RefreshUpdatedMods();
var package = ContentPackageManager.WorkshopPackages.FirstOrDefault(p => p.SteamWorkshopId == workshopItem.Id);
if (package is RegularPackage regular)
{
ContentPackageManager.EnabledPackages.EnableRegular(regular);
}
PopulateInstalledModLists(forceRefreshEnabled: true);
});
return false;
}

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.18.6.0</Version>
<Version>0.18.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.18.6.0</Version>
<Version>0.18.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.18.6.0</Version>
<Version>0.18.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.18.6.0</Version>
<Version>0.18.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.18.6.0</Version>
<Version>0.18.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -10,6 +10,11 @@ namespace Barotrauma
{
private readonly Dictionary<Identifier, float> prevSentSkill = new Dictionary<Identifier, float>();
/// <summary>
/// The client opted to create a new character and discard this one
/// </summary>
public bool Discarded;
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel)
{
if (Character == null || Character.Removed) { return; }

View File

@@ -230,7 +230,7 @@ namespace Barotrauma
if (!matchingCharacterData.HasSpawned) { continue; }
characterInfo ??= matchingCharacterData.CharacterInfo;
}
if (characterInfo == null) { continue; }
if (characterInfo == null || characterInfo.Discarded) { continue; }
//reduce skills if the character has died
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
{
@@ -420,6 +420,8 @@ namespace Barotrauma
{
discardedCharacters.Add(data);
}
DebugConsole.Log($"Client \"{client}\" discarded the character ({data.Name})");
data.CharacterInfo.Discarded = true;
characterData.Remove(data);
IncrementLastUpdateIdForFlag(NetFlags.CharacterInfo);
}

View File

@@ -1,4 +1,5 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Networking;
@@ -18,7 +19,8 @@ namespace Barotrauma
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte) ServerPacketHeader.READY_CHECK);
msg.Write((byte) ReadyCheckState.Start);
msg.Write(endTime);
msg.Write(new DateTimeOffset(startTime).ToUnixTimeSeconds());
msg.Write(new DateTimeOffset(endTime).ToUnixTimeSeconds());
msg.Write(author);
if (sender != null)
@@ -53,10 +55,9 @@ namespace Barotrauma
foreach (Client client in ActivePlayers)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte) ServerPacketHeader.READY_CHECK);
msg.Write((byte) ReadyCheckState.Update);
msg.Write(time); // sync time
msg.Write((byte) state);
msg.Write((byte)ServerPacketHeader.READY_CHECK);
msg.Write((byte)ReadyCheckState.Update);
msg.Write((byte)state);
msg.Write(otherClient);
GameMain.Server.ServerPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
}

View File

@@ -1,13 +1,22 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Globalization;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Pump : Powered, IServerSerializable, IClientSerializable
{
const float NetworkUpdateInterval = 5.0f;
private float networkUpdateTimer;
partial void UpdateProjSpecific(float deltaTime)
{
networkUpdateTimer -= deltaTime;
if (networkUpdateTimer <= 0.0f)
{
item.CreateServerEvent(this);
networkUpdateTimer = NetworkUpdateInterval;
}
}
public void ServerEventRead(IReadMessage msg, Client c)
{
float newFlowPercentage = msg.ReadRangedInteger(-10, 10) * 10.0f;

View File

@@ -2,10 +2,7 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
using Barotrauma.MapCreatures.Behavior;
namespace Barotrauma
{
@@ -39,9 +36,9 @@ namespace Barotrauma
return;
}
statusUpdateTimer -= deltaTime;
decalUpdateTimer -= deltaTime;
backgroundSectionUpdateTimer -= deltaTime;
statusUpdateTimer += deltaTime;
decalUpdateTimer += deltaTime;
backgroundSectionUpdateTimer += deltaTime;
//update client hulls if the amount of water has changed by >10%
//or if oxygen percentage has changed by 5%
@@ -49,33 +46,32 @@ namespace Barotrauma
(Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f
|| Math.Abs(lastSentOxygen - OxygenPercentage) > 5f
|| lastSentFireCount != FireSources.Count)
&& statusUpdateTimer <= 0.0f;
&& (statusUpdateTimer > NetConfig.HullUpdateInterval);
if (shouldSendStatusUpdate)
//force an update every 5 seconds even if nothing's changed (in case a client's gotten out of sync somehow)
if (shouldSendStatusUpdate || statusUpdateTimer > NetConfig.SparseHullUpdateInterval)
{
GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData());
GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData());
lastSentVolume = waterVolume;
lastSentOxygen = OxygenPercentage;
lastSentFireCount = FireSources.Count;
statusUpdateTimer = NetConfig.SparseHullUpdateInterval;
statusUpdateTimer = 0;
}
if (decalUpdatePending && decalUpdateTimer <= 0.0f)
if (decalUpdatePending && decalUpdateTimer > NetConfig.HullUpdateInterval)
{
GameMain.NetworkMember.CreateEntityEvent(this, new DecalEventData());
decalUpdateTimer = NetConfig.HullUpdateInterval;
decalUpdateTimer = 0;
decalUpdatePending = false;
}
if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer <= 0.0f)
if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer > NetConfig.HullUpdateInterval)
{
foreach (int pendingSectionUpdate in pendingSectionUpdates)
{
GameMain.NetworkMember.CreateEntityEvent(this, new BackgroundSectionsEventData(pendingSectionUpdate));
}
backgroundSectionUpdateTimer = NetConfig.HullUpdateInterval;
backgroundSectionUpdateTimer = 0;
pendingSectionUpdates.Clear();
}
}

View File

@@ -73,6 +73,9 @@ namespace Barotrauma.Networking
characterInfo = value;
}
}
public string PendingName;
public NetworkConnection Connection { get; set; }
public bool SpectateOnly;

View File

@@ -1046,7 +1046,7 @@ namespace Barotrauma.Networking
c.LastRecvChatMsgID = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvChatMsgID, c.LastChatMsgQueueID);
c.LastRecvClientListUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvClientListUpdate, LastClientListUpdateID);
TryChangeClientName(c, inc);
ReadClientNameChange(c, inc);
c.LastRecvCampaignSave = inc.ReadUInt16();
if (c.LastRecvCampaignSave > 0)
@@ -2675,7 +2675,7 @@ namespace Barotrauma.Networking
base.AddChatMessage(message);
}
private bool TryChangeClientName(Client c, IReadMessage inc)
private bool ReadClientNameChange(Client c, IReadMessage inc)
{
UInt16 nameId = inc.ReadUInt16();
string newName = inc.ReadString();
@@ -2685,16 +2685,21 @@ namespace Barotrauma.Networking
if (c == null || string.IsNullOrEmpty(newName) || !NetIdUtils.IdMoreRecent(nameId, c.NameID)) { return false; }
c.NameID = nameId;
newName = Client.SanitizeName(newName);
if (newName == c.Name && newJob == c.PreferredJob && newTeam == c.PreferredTeam) { return false; }
c.PreferredJob = newJob;
c.PreferredTeam = newTeam;
return TryChangeClientName(c, newName);
}
public bool TryChangeClientName(Client c, string newName)
{
newName = Client.SanitizeName(newName);
//update client list even if the name cannot be changed to the one sent by the client,
//so the client will be informed what their actual name is
LastClientListUpdateID++;
if (newName == c.Name) { return false; }
if (newName == c.Name || string.IsNullOrEmpty(newName)) { return false; }
if (IsNameValid(c, newName))
{
@@ -2710,6 +2715,7 @@ namespace Barotrauma.Networking
}
}
private bool IsNameValid(Client c, string newName)
{
newName = Client.SanitizeName(newName);
@@ -3542,6 +3548,10 @@ namespace Barotrauma.Networking
{
newName = sender.Name;
}
else
{
sender.PendingName = newName;
}
}
int tagCount = message.ReadByte();

View File

@@ -392,6 +392,14 @@ namespace Barotrauma.Networking
bool forceSpawnInMainSub = false;
if (!bot && campaign != null)
{
//the client has opted to change the name of their new character
//when the character spawns, set the client's name to match
if (clients[i].PendingName == characterInfos[i].Name)
{
GameMain.Server?.TryChangeClientName(clients[i], clients[i].PendingName);
clients[i].PendingName = null;
}
var matchingData = campaign?.GetClientCharacterData(clients[i]);
if (matchingData != null)
{

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.18.6.0</Version>
<Version>0.18.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -227,9 +227,13 @@ namespace Barotrauma
{
mainLimb = Limbs.FirstOrDefault(l => IsValid(l));
}
if (mainLimb == null)
{
DebugConsole.ThrowError("Couldn't find a valid main limb. The limb can't be hidden nor be set to ignore collisions!");
mainLimb = Limbs.FirstOrDefault();
}
}
bool IsValid(Limb limb) => limb != null && !limb.IsSevered && !limb.IgnoreCollisions && !limb.Hidden;
static bool IsValid(Limb limb) => limb != null && !limb.IsSevered && !limb.IgnoreCollisions && !limb.Hidden;
return mainLimb;
}
}

View File

@@ -49,6 +49,9 @@ namespace Barotrauma
[Serialize("", IsPropertySaveable.Yes)]
public Identifier SpawnPointTag { get; set; }
[Serialize(CharacterTeamType.FriendlyNPC, IsPropertySaveable.Yes)]
public CharacterTeamType Team { get; protected set; }
[Serialize(false, IsPropertySaveable.Yes, description: "Should we spawn the entity even when no spawn points with matching tags were found?")]
public bool RequireSpawnPointTag { get; set; }
@@ -119,7 +122,7 @@ namespace Barotrauma
{
if (newCharacter == null) { return; }
newCharacter.HumanPrefab = humanPrefab;
newCharacter.TeamID = CharacterTeamType.FriendlyNPC;
newCharacter.TeamID = Team;
newCharacter.EnableDespawn = false;
humanPrefab.GiveItems(newCharacter, newCharacter.Submarine);
if (LootingIsStealing)

View File

@@ -13,12 +13,26 @@ namespace Barotrauma
internal partial class ReadyCheck
{
private readonly float endTime;
private float time;
private readonly DateTime endTime;
private readonly DateTime startTime;
public readonly Dictionary<byte, ReadyStatus> Clients;
public bool IsFinished = false;
public ReadyCheck(List<byte> clients, float duration = 30)
public ReadyCheck(List<byte> clients, DateTime startTime, DateTime endTime)
: this(clients)
{
this.startTime = startTime;
this.endTime = endTime;
}
public ReadyCheck(List<byte> clients, float duration)
: this(clients)
{
startTime = DateTime.Now;
endTime = startTime + new TimeSpan(0, 0, 0, 0, (int)(duration * 1000));
}
private ReadyCheck(List<byte> clients)
{
Clients = new Dictionary<byte, ReadyStatus>();
foreach (byte client in clients)
@@ -27,24 +41,17 @@ namespace Barotrauma
Clients.Add(client, ReadyStatus.Unanswered);
}
time = duration;
endTime = duration;
#if CLIENT
lastSecond = (int) Math.Ceiling(duration);
#endif
}
partial void EndReadyCheck();
public void Update(float deltaTime)
{
if (time > 0)
if (DateTime.Now < endTime)
{
#if CLIENT
UpdateBar();
#endif
time -= deltaTime;
return;
}

View File

@@ -1,10 +1,9 @@
using Barotrauma.Networking;
using Barotrauma.MapCreatures.Behavior;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.MapCreatures.Behavior;
namespace Barotrauma.Items.Components
{
@@ -24,7 +23,10 @@ namespace Barotrauma.Items.Components
if (value == hijacked) { return; }
hijacked = value;
#if SERVER
item.CreateServerEvent(this);
if (!Submarine.Unloading)
{
item.CreateServerEvent(this);
}
#endif
}
}

View File

@@ -68,7 +68,7 @@ namespace Barotrauma.Items.Components
get { return poweredList; }
}
public static readonly List<Connection> ChangedConnections = new List<Connection>();
public static readonly HashSet<Connection> ChangedConnections = new HashSet<Connection>();
public readonly static Dictionary<int, GridInfo> Grids = new Dictionary<int, GridInfo>();
@@ -158,6 +158,12 @@ namespace Barotrauma.Items.Components
}
}
/// <summary>
/// Essentially Voltage / MinVoltage (= how much of the minimum required voltage has been satisfied), clamped between 0 and 1.
/// Can be used by status effects or sounds to check if the item has enough power to run
/// </summary>
public float RelativeVoltage => minVoltage <= 0.0f ? 1.0f : MathHelper.Clamp(Voltage / minVoltage, 0.0f, 1.0f);
public bool PoweredByTinkering { get; set; }
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the item be damaged by electomagnetic pulses.")]

View File

@@ -170,6 +170,7 @@ namespace Barotrauma.Items.Components
public void SetRecipientsDirty()
{
recipientsDirty = true;
if (IsPower) { Powered.ChangedConnections.Add(this); }
}
private void RefreshRecipients()

View File

@@ -399,6 +399,7 @@ namespace Barotrauma.MapCreatures.Behavior
new XAttribute("pos", XMLExtensions.Vector2ToString(branch.Position)),
new XAttribute("ID", branch.ID),
new XAttribute("isroot", branch.IsRoot),
new XAttribute("isrootgrowth", branch.IsRootGrowth),
new XAttribute("health", branch.Health.ToString("G", CultureInfo.InvariantCulture)),
new XAttribute("maxhealth", branch.MaxHealth.ToString("G", CultureInfo.InvariantCulture)),
new XAttribute("sides", (int)branch.Sides),
@@ -457,9 +458,16 @@ namespace Barotrauma.MapCreatures.Behavior
foreach ((BallastFloraBranch branch, int parentBranchId) in branches)
{
if (parentBranchId > -1 && parentBranchId < Branches.Count)
if (parentBranchId > -1)
{
branch.ParentBranch = Branches[parentBranchId];
if (parentBranchId < Branches.Count)
{
branch.ParentBranch = Branches[parentBranchId];
}
else
{
DebugConsole.AddWarning($"Error while loading ballast flora: parent branch ID {parentBranchId} out of range (total {Branches.Count} branches)");
}
}
}
@@ -476,6 +484,7 @@ namespace Barotrauma.MapCreatures.Behavior
{
Vector2 pos = branchElement.GetAttributeVector2("pos", Vector2.Zero);
bool isRoot = branchElement.GetAttributeBool("isroot", false);
bool isRootGrowth = branchElement.GetAttributeBool("isrootgrowth", false);
int flowerConfig = getInt("flowerconfig");
int leafconfig = getInt("leafconfig");
int id = getInt("ID");
@@ -493,7 +502,8 @@ namespace Barotrauma.MapCreatures.Behavior
MaxHealth = maxhealth,
Sides = (TileSide) sides,
BlockedSides = (TileSide) blockedSides,
IsRoot = isRoot
IsRoot = isRoot,
IsRootGrowth = isRootGrowth
};
branches.Add((newBranch, parentBranchId));
@@ -658,11 +668,14 @@ namespace Barotrauma.MapCreatures.Behavior
toBeRemoved.Clear();
foreach (BallastFloraBranch branch in Branches)
{
if (branch.ParentBranch == null || branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f)
if (!branch.IsRoot)
{
float parentHealth = branch.ParentBranch == null ? 0.0f : branch.ParentBranch.Health / branch.ParentBranch.MaxHealth;
float speed = MathHelper.Lerp(5.0f, 0.1f, parentHealth);
DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot);
if (branch.ParentBranch == null || branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f)
{
float parentHealth = branch.ParentBranch == null ? 0.0f : branch.ParentBranch.Health / branch.ParentBranch.MaxHealth;
float speed = MathHelper.Lerp(5.0f, 0.1f, parentHealth);
DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot);
}
}
if (branch.Health <= 0.0f)
{
@@ -1197,7 +1210,10 @@ namespace Barotrauma.MapCreatures.Behavior
}
});
#if SERVER
CreateNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null));
if (!item.Removed && Parent != null && !Parent.Removed)
{
CreateNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null));
}
#endif
}

View File

@@ -215,16 +215,19 @@ namespace Barotrauma
saveElement = element
};
if (!string.IsNullOrWhiteSpace(levelSeed) && levelData != null &&
levelData.Seed != levelSeed && !linkedSub.purchasedLostShuttles)
{
linkedSub.loadSub = false;
}
else
bool levelMatches = string.IsNullOrWhiteSpace(levelSeed) || levelData == null || levelData.Seed == levelSeed;
//don't load a sub that was left in this level if we have a submarine switch pending
//to make sure it gets ignored during the submarine switch and item transfer (reloading and saving it during the switch makes it not considered "left behind")
if ((levelMatches || linkedSub.purchasedLostShuttles) && GameMain.GameSession?.Campaign?.PendingSubmarineSwitch == null)
{
linkedSub.loadSub = true;
linkedSub.rect.Location = MathUtils.ToPoint(pos);
}
else
{
linkedSub.loadSub = false;
}
}
#warning TODO: revise
@@ -279,14 +282,14 @@ namespace Barotrauma
if (worldPos != Vector2.Zero)
{
if (GameMain.GameSession != null && GameMain.GameSession.MirrorLevel)
{
{
worldPos.X = GameMain.GameSession.LevelData.Size.X - worldPos.X;
}
sub.SetPosition(worldPos);
}
else
{
sub.SetPosition(WorldPosition);
sub.SetPosition(WorldPosition);
}
DockingPort linkedPort = null;
@@ -308,8 +311,17 @@ namespace Barotrauma
{
linkedPort = (FindEntityByID(originalLinkedToID) as Item)?.GetComponent<DockingPort>();
}
if (linkedPort == null) { return; }
}
if (linkedPort == null)
{
if (worldPos == Vector2.Zero)
{
DebugConsole.ThrowError("Something went wrong when loading a linked submarine - the save didn't include either a world position or a linked port for the submarine.");
}
return;
}
originalLinkedPort = linkedPort;
ushort originalMyId = childRemap.GetOffsetId(originalMyPortID);

View File

@@ -1,11 +1,9 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -98,9 +96,29 @@ namespace Barotrauma
[Serialize("", IsPropertySaveable.Yes), Editable]
public string ReplaceInRadiation { get; set; }
private readonly Dictionary<Identifier, int> moduleCounts = new Dictionary<Identifier, int>();
public class ModuleCount
{
public Identifier Identifier;
public int Count;
public int Order;
public IReadOnlyDictionary<Identifier, int> ModuleCounts
public ModuleCount(ContentXElement element)
{
Identifier = element.GetAttributeIdentifier("flag", element.GetAttributeIdentifier("moduletype", ""));
Count = element.GetAttributeInt("count", 0);
Order = element.GetAttributeInt("order", 0);
}
public ModuleCount(Identifier id, int count)
{
Identifier = id;
Count = count;
}
}
private readonly List<ModuleCount> moduleCounts = new List<ModuleCount>();
public IReadOnlyList<ModuleCount> ModuleCounts
{
get { return moduleCounts; }
}
@@ -171,8 +189,7 @@ namespace Barotrauma
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "modulecount":
Identifier moduleFlag = subElement.GetAttributeIdentifier("flag", subElement.GetAttributeIdentifier("moduletype", ""));
moduleCounts[moduleFlag] = subElement.GetAttributeInt("count", 0);
moduleCounts.Add(new ModuleCount(subElement));
break;
case "npcs":
var newCollection = new NpcCollection();
@@ -200,7 +217,7 @@ namespace Barotrauma
public int GetModuleCount(Identifier moduleFlag)
{
if (moduleFlag == Identifier.Empty || moduleFlag == "none") { return int.MaxValue; }
return moduleCounts.ContainsKey(moduleFlag) ? moduleCounts[moduleFlag] : 0;
return moduleCounts.FirstOrDefault(m => m.Identifier == moduleFlag)?.Count ?? 0;
}
public void SetModuleCount(Identifier moduleFlag, int count)
@@ -208,11 +225,19 @@ namespace Barotrauma
if (moduleFlag == Identifier.Empty || moduleFlag == "none") { return; }
if (count <= 0)
{
moduleCounts.Remove(moduleFlag);
moduleCounts.RemoveAll(m => m.Identifier == moduleFlag);
}
else
{
moduleCounts[moduleFlag] = count;
var moduleCount = moduleCounts.FirstOrDefault(m => m.Identifier == moduleFlag);
if (moduleCount == null)
{
moduleCounts.Add(new ModuleCount(moduleFlag, count));
}
else
{
moduleCount.Count = count;
}
}
}

View File

@@ -99,7 +99,7 @@ namespace Barotrauma
{
//if the module doesn't have the ruin flag or any other flag used in the generation params, don't use it in ruins
if (!subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin".ToIdentifier()) &&
!generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Key)))
!generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Identifier)))
{
continue;
}
@@ -141,16 +141,11 @@ namespace Barotrauma
selectedModules.Clear();
//select which module types the outpost should consist of
List<Identifier> pendingModuleFlags;
using (var md5 = MD5.Create())
{
#warning TODO: cursed
pendingModuleFlags = onlyEntrance
? generationParams.ModuleCounts
.Keys.OrderBy(k => ToolBox.IdentifierToUint32Hash(k, md5))
.First().ToEnumerable().ToList()
: SelectModules(outpostModules, generationParams);
}
List<Identifier> pendingModuleFlags =
onlyEntrance ?
generationParams.ModuleCounts.First().Identifier.ToEnumerable().ToList() :
SelectModules(outpostModules, generationParams);
foreach (Identifier flag in pendingModuleFlags)
{
if (flag == "none") { continue; }
@@ -437,31 +432,27 @@ namespace Barotrauma
var pendingModuleFlags = new List<Identifier>();
bool availableModulesFound = true;
Identifier initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Key;
Identifier initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Identifier;
pendingModuleFlags.Add(initialModuleFlag);
while (pendingModuleFlags.Count < totalModuleCount && availableModulesFound)
{
availableModulesFound = false;
foreach (var moduleFlag in generationParams.ModuleCounts)
{
if (pendingModuleFlags.Count(m => m == moduleFlag.Key) >= generationParams.GetModuleCount(moduleFlag.Key))
if (pendingModuleFlags.Count(m => m == moduleFlag.Identifier) >= generationParams.GetModuleCount(moduleFlag.Identifier))
{
continue;
}
if (!modules.Any(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag.Key)))
if (!modules.Any(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag.Identifier)))
{
DebugConsole.ThrowError($"Failed to add a module to the outpost (no modules with the flag \"{moduleFlag.Key}\" found).");
DebugConsole.ThrowError($"Failed to add a module to the outpost (no modules with the flag \"{moduleFlag.Identifier}\" found).");
continue;
}
availableModulesFound = true;
pendingModuleFlags.Add(moduleFlag.Key);
pendingModuleFlags.Add(moduleFlag.Identifier);
}
}
using (MD5 md5 = MD5.Create())
{
pendingModuleFlags.Sort((i1, i2) => (int)ToolBox.StringToUInt32Hash(i1.Value.ToLowerInvariant(), md5) - (int)ToolBox.StringToUInt32Hash(i2.Value.ToLowerInvariant(), md5));
}
pendingModuleFlags.Shuffle(Rand.RandSync.ServerAndClient);
pendingModuleFlags.OrderBy(f => generationParams.ModuleCounts.First(m => m.Identifier == f)).ThenBy(f => Rand.Value(Rand.RandSync.ServerAndClient));
while (pendingModuleFlags.Count < totalModuleCount)
{
//don't place "none" modules at the end because
@@ -610,7 +601,7 @@ namespace Barotrauma
Identifier flagToPlace = "none".ToIdentifier();
SubmarineInfo nextModule = null;
foreach (Identifier moduleFlag in pendingModuleFlags)
foreach (Identifier moduleFlag in pendingModuleFlags.OrderByDescending(f => currentModule?.Info?.OutpostModuleInfo.AllowAttachToModules.Contains(f) ?? false))
{
flagToPlace = moduleFlag;
nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType, allowDifferentLocationType);
@@ -1048,6 +1039,17 @@ namespace Barotrauma
module.ThisGapPosition == OutpostModuleInfo.GapPosition.Left ||
module.ThisGapPosition == OutpostModuleInfo.GapPosition.Right;
if (!module.ThisGap.linkedTo.Any())
{
DebugConsole.ThrowError($"Error during outpost generation: {module.ThisGapPosition} gap in module \"{module.Info.Name}\" was not linked to any hulls.");
continue;
}
if (!module.PreviousGap.linkedTo.Any())
{
DebugConsole.ThrowError($"Error during outpost generation: {GetOpposingGapPosition(module.ThisGapPosition)} gap in module \"{module.PreviousModule.Info.Name}\" was not linked to any hulls.");
continue;
}
MapEntity leftHull = module.ThisGap.Position.X < module.PreviousGap.Position.X ? module.ThisGap.linkedTo[0] : module.PreviousGap.linkedTo[0];
MapEntity rightHull = module.ThisGap.Position.X > module.PreviousGap.Position.X ?
module.ThisGap.linkedTo.Count == 1 ? module.ThisGap.linkedTo[0] : module.ThisGap.linkedTo[1] :

View File

@@ -109,6 +109,8 @@ namespace Barotrauma
public bool IsCampaignCompatible => IsPlayer && !HasTag(SubmarineTag.Shuttle) && !HasTag(SubmarineTag.HideInMenus) && SubmarineClass != SubmarineClass.Undefined;
public bool IsCampaignCompatibleIgnoreClass => IsPlayer && !HasTag(SubmarineTag.Shuttle) && !HasTag(SubmarineTag.HideInMenus);
public bool AllowPreviewImage => Type == SubmarineType.Player;
public Md5Hash MD5Hash
{
get
@@ -556,7 +558,7 @@ namespace Barotrauma
XDocument doc = new XDocument(newElement);
doc.Root.Add(new XAttribute("name", Name));
if (previewImage != null)
if (previewImage != null && AllowPreviewImage)
{
doc.Root.Add(new XAttribute("previewimage", Convert.ToBase64String(previewImage.ToArray())));
}

View File

@@ -619,6 +619,11 @@ namespace Barotrauma
if (parentObject is Powered powered) { value = powered.Voltage; return true; }
}
break;
case nameof(Powered.RelativeVoltage):
{
if (parentObject is Powered powered) { value = powered.RelativeVoltage; return true; }
}
break;
case nameof(Powered.CurrPowerConsumption):
{
if (parentObject is Powered powered) { value = powered.CurrPowerConsumption; return true; }

View File

@@ -480,6 +480,8 @@ namespace Barotrauma
bool voiceCaptureChanged = currentConfig.Audio.VoiceCaptureDevice != newConfig.Audio.VoiceCaptureDevice;
bool textScaleChanged = Math.Abs(currentConfig.Graphics.TextScale - newConfig.Graphics.TextScale) > MathF.Pow(2.0f, -7);
bool hudScaleChanged = !MathUtils.NearlyEqual(currentConfig.Graphics.HUDScale, newConfig.Graphics.HUDScale);
bool setGraphicsMode =
resolutionChanged ||
currentConfig.Graphics.VSync != newConfig.Graphics.VSync ||
@@ -514,6 +516,10 @@ namespace Barotrauma
componentStyle.RefreshSize();
}
}
if (hudScaleChanged)
{
HUDLayoutSettings.CreateAreas();
}
GameMain.SoundManager?.ApplySettings();
#endif

View File

@@ -100,13 +100,23 @@ namespace Barotrauma
}
#endif
if (Path.IsPathRooted(originalFilename))
string startPath = directory ?? "";
string saveFolder = SaveUtil.SaveFolder.Replace('\\', '/');
if (originalFilename.Replace('\\', '/').StartsWith(saveFolder))
{
//paths that lead to the save folder might have incorrect case,
//mainly if they come from a filelist
startPath = saveFolder.EndsWith('/') ? saveFolder : $"{saveFolder}/";
filename = startPath;
subDirs = subDirs.Skip(saveFolder.Split('/').Length).ToArray();
}
else if (Path.IsPathRooted(originalFilename))
{
#warning TODO: incorrect assumption or...? Figure out what this was actually supposed to fix, if anything. Might've been a perf thing.
return originalFilename; //assume that rooted paths have correct case since these are generated by the game
}
string startPath = directory ?? "";
for (int i = 0; i < subDirs.Length; i++)
{
if (i == subDirs.Length - 1 && string.IsNullOrEmpty(subDirs[i]))

View File

@@ -1,3 +1,41 @@
---------------------------------------------------------------------------------------------------------
v0.18.7.0
---------------------------------------------------------------------------------------------------------
Unstable only:
- Reduced depth charge scale to fit in loader/racks better.
- Fixed ballast flora dying by itself client-side when transitioning to a new level.
- Disallow laying in vertically flipped normal bunks.
- Fixed broken door sprite stretching on the wrong axis when cutting a door.
- Fixed AI orders not working in multiplayer.
- Fixed tutorial characters starting with more items than they should.
- Fixed chat box closing when clicking any chat box elements after opening it with the keybind.
- Fixed submarine selection resetting when changing server settings in the campaign setup menu.
- Fixed "enable" and "disable" being wrong way around in the mod tab's context menus.
- Fixed sub editor always saving subs from a local mod in the root of that mod's folder instead of the actual location of that sub file.
- Fixed decoys not being containable in wrecked coilgun ammo shelves.
- Fixes and improvements to the new beacon stations and the enemies inside them.
- Fixed an issue during submarine switching when a drone / linked sub has been left behind (Regalis11/Barotrauma#9172): When you were switching back to a submarine whose drone you'd left behind, in the same level where you left the drone, the drone would get loaded and resaved during the item transfer, which caused it to no longer be considered "left behind". It also removed the drone's position from the save, and since it was not docked to anything either, positioning it failed at the beginning of the next round.
Changes:
- Adding preview images to wrecks, beacon stations, outposts or enemy subs isn't allowed in the sub editor (unnecessarily bloats up their file size, as the preview images aren't visible anywhere).
Fixes:
- Fixed server not refreshing the power grid when a client disconnects and reconnects a power wire.
- Fixed hull updates not being sent if the water/oxygen/fire in the hull doesn't change server-side, preventing the hull's status from getting corrected if a client somehow ends up out of sync.
- Fixed keybinds shown in the controls tab not refreshing when resetting the binds.
- Hopefully fixed colonies sometimes not including some modules (most often the armory module).
- Fixed ready checks sometimes ending at a slightly different time client-side compared to the server, allowing you to answer the prompt even though the time to answer already ended server-side.
- Fixed large terminal welcome messages going slightly outside the bounds of the listbox.
- Fixed overlapping in the tab menu's mission tab when there's more than one mission selected.
- Fixed fabricators and deconstructors playing the sounds even if they're out of power.
- Fixed occasional "hash mismatch for downloaded mod" errors on Linux.
- Fixed clients occasionally spawning as the old character after they've opted to create a new one. Only happened if the client hadn't died and was still controlling the old character at the end of the round.
- When a client creates a character with a new name, the client's name is changed to match it after they spawn as that character.
- Fixed enabled mods getting disabled when updating them in the mods menu.
- Fixed a rounding error in Sprite.DrawTiled that sometimes caused an extra 1-pixel line on some scaled and flipped structures (e.g. certain wall pieces scaled to 0.6).
- Fixed Orca 2 still using the old chaingun charge time.
---------------------------------------------------------------------------------------------------------
v0.18.6.0
---------------------------------------------------------------------------------------------------------