Build 0.18.13.0

This commit is contained in:
Markus Isberg
2022-07-01 12:16:36 +09:00
parent 8e6c601162
commit 497045de7e
79 changed files with 717 additions and 361 deletions

View File

@@ -685,6 +685,7 @@ namespace Barotrauma
causeOfDeathAffliction = AfflictionPrefab.Prefabs[afflictionName];
}
}
bool containsAfflictionData = msg.ReadBoolean();
if (!IsDead)
{
if (causeOfDeathType == CauseOfDeathType.Pressure || causeOfDeathAffliction == AfflictionPrefab.Pressure)
@@ -695,6 +696,11 @@ namespace Barotrauma
{
Kill(causeOfDeathType, causeOfDeathAffliction?.Instantiate(1.0f), true);
}
}
if (containsAfflictionData)
{
CharacterHealth.ClientRead(msg);
CharacterHealth.ForceUpdateVisuals();
}
}
else

View File

@@ -2011,7 +2011,6 @@ namespace Barotrauma
partial void UpdateSkinTint()
{
if (!Character.IsVisible) { return; }
FaceTint = DefaultFaceTint;
BodyTint = Color.TransparentBlack;
@@ -2029,7 +2028,6 @@ namespace Barotrauma
partial void UpdateLimbAfflictionOverlays()
{
if (!Character.IsVisible) { return; }
foreach (Limb limb in Character.AnimController.Limbs)
{
if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { continue; }

View File

@@ -1750,9 +1750,9 @@ namespace Barotrauma
addIfMissing($"missionfailure.{missionId}".ToIdentifier(), language);
}
}
for (int i = 0; i<missionPrefab.Messages.Length; i++)
for (int i = 0; i < missionPrefab.Messages.Length; i++)
{
if (missionPrefab.Messages[i].IsNullOrWhiteSpace())
if (missionPrefab.Messages[i].IsNullOrWhiteSpace() || (missionPrefab.Messages[i] as FallbackLString)?.GetLastFallback() is FallbackLString { PrimaryIsLoaded: false })
{
addIfMissing($"MissionMessage{i}.{missionId}".ToIdentifier(), language);
}

View File

@@ -47,7 +47,9 @@ namespace Barotrauma
CreateUI();
UpdateLocationView(campaignUI.Campaign.Map.CurrentLocation, true);
campaignUI.Campaign.Map.OnLocationChanged += (prevLocation, newLocation) => UpdateLocationView(newLocation, true, prevLocation);
campaignUI.Campaign.Map.OnLocationChanged.RegisterOverwriteExisting(
"CrewManagement.UpdateLocationView".ToIdentifier(),
(locationChangeInfo) => UpdateLocationView(locationChangeInfo.NewLocation, true, locationChangeInfo.PrevLocation));
}
public void RefreshPermissions()

View File

@@ -20,7 +20,7 @@ namespace Barotrauma
private RectTransform currentHighestParent;
private List<RectTransform> parentHierarchy = new List<RectTransform>();
private bool selectMultiple;
private readonly bool selectMultiple;
public bool Dropped { get; set; }
@@ -129,18 +129,20 @@ namespace Barotrauma
}
}
private List<object> selectedDataMultiple = new List<object>();
private readonly List<object> selectedDataMultiple = new List<object>();
public IEnumerable<object> SelectedDataMultiple
{
get { return selectedDataMultiple; }
}
private List<int> selectedIndexMultiple = new List<int>();
private readonly List<int> selectedIndexMultiple = new List<int>();
public IEnumerable<int> SelectedIndexMultiple
{
get { return selectedIndexMultiple; }
}
public bool MustSelectAtLeastOne;
public LocalizedString Text
{
get { return button.Text; }
@@ -269,6 +271,12 @@ namespace Barotrauma
ToolTip = toolTip,
OnSelected = (GUITickBox tb) =>
{
if (MustSelectAtLeastOne && selectedIndexMultiple.Count <= 1 && !tb.Selected)
{
tb.Selected = true;
return false;
}
List<LocalizedString> texts = new List<LocalizedString>();
selectedDataMultiple.Clear();
selectedIndexMultiple.Clear();

View File

@@ -188,21 +188,23 @@ namespace Barotrauma
this.parentComponent = parentComponent;
UpdatePermissions();
CreateUI();
campaignUI.Campaign.Map.OnLocationChanged += UpdateLocation;
if (CurrentLocation?.Reputation != null)
{
CurrentLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
}
campaignUI.Campaign.CargoManager.OnItemsInBuyCrateChanged += () => { needsBuyingRefresh = true; };
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += () => { needsRefresh = true; };
campaignUI.Campaign.CargoManager.OnItemsInSellCrateChanged += () => { needsSellingRefresh = true; };
campaignUI.Campaign.CargoManager.OnSoldItemsChanged += () =>
Identifier refreshStoreId = new Identifier("RefreshStore");
campaignUI.Campaign.Map.OnLocationChanged.RegisterOverwriteExisting(
refreshStoreId,
(locationChangeInfo) => UpdateLocation(locationChangeInfo.PrevLocation, locationChangeInfo.NewLocation));
CurrentLocation?.Reputation?.OnReputationValueChanged.RegisterOverwriteExisting(refreshStoreId, _ => needsRefresh = true);
CargoManager cargoManager = campaignUI.Campaign.CargoManager;
cargoManager.OnItemsInBuyCrateChanged.RegisterOverwriteExisting(refreshStoreId, _ => needsBuyingRefresh = true);
cargoManager.OnPurchasedItemsChanged.RegisterOverwriteExisting(refreshStoreId, _ => needsRefresh = true);
cargoManager.OnItemsInSellCrateChanged.RegisterOverwriteExisting(refreshStoreId, _ => needsSellingRefresh = true);
cargoManager.OnSoldItemsChanged.RegisterOverwriteExisting(refreshStoreId, _ =>
{
needsItemsToSellRefresh = true;
needsItemsToSellFromSubRefresh = true;
needsRefresh = true;
};
campaignUI.Campaign.CargoManager.OnItemsInSellFromSubCrateChanged += () => { needsSellingFromSubRefresh = true; };
});
cargoManager.OnItemsInSellFromSubCrateChanged.RegisterOverwriteExisting(refreshStoreId, _ => needsSellingFromSubRefresh = true);
}
public void SelectStore(Identifier identifier)
@@ -713,7 +715,7 @@ namespace Barotrauma
if (prevLocation == newLocation) { return; }
if (prevLocation?.Reputation != null)
{
prevLocation.Reputation.OnReputationValueChanged -= SetNeedsRefresh;
prevLocation.Reputation.OnReputationValueChanged.Dispose();
}
if (ItemPrefab.Prefabs.Any(p => p.CanBeBoughtFrom(newLocation)))
{
@@ -722,7 +724,7 @@ namespace Barotrauma
ChangeStoreTab(StoreTab.Buy);
if (newLocation?.Reputation != null)
{
newLocation.Reputation.OnReputationValueChanged += SetNeedsRefresh;
CurrentLocation.Reputation.OnReputationValueChanged.RegisterOverwriteExisting("RefreshStore".ToIdentifier(), _ => { SetNeedsRefresh(); });
}
}

View File

@@ -4,7 +4,6 @@ using Microsoft.Xna.Framework;
using System.Linq;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Globalization;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
@@ -30,12 +29,12 @@ namespace Barotrauma
private int selectionIndicatorThickness;
private GUIImage listBackground;
private GUITickBox transferItemsTickBox;
private GUITextBlock itemTransferReminderBlock;
private GUITextBlock itemTransferInfoBlock;
private readonly List<SubmarineInfo> subsToShow;
private readonly SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
private SubmarineInfo selectedSubmarine = null;
private LocalizedString purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, switchText, missingPreviewText, currencyName;
private LocalizedString purchaseAndSwitchText, purchaseOnlyText, deliveryText, selectedSubText, switchText, missingPreviewText, currencyName;
private readonly RectTransform parent;
private readonly Action closeAction;
private Sprite pageIndicator;
@@ -107,7 +106,7 @@ namespace Barotrauma
private void Initialize()
{
initialized = true;
currentSubText = TextManager.Get("currentsub");
selectedSubText = TextManager.Get("selectedsub");
deliveryText = TextManager.Get("requestdeliverybutton");
switchText = TextManager.Get("switchtosubmarinebutton");
purchaseAndSwitchText = TextManager.Get("purchaseandswitch");
@@ -203,7 +202,7 @@ namespace Barotrauma
OnSelected = (tb) => transferItemsOnSwitch = tb.Selected
};
transferItemsTickBox.RectTransform.Resize(new Point(Math.Min((int)transferItemsTickBox.ContentWidth, transferInfoFrame.Rect.Width), transferItemsTickBox.Rect.Height));
itemTransferReminderBlock = new GUITextBlock(new RectTransform(Vector2.One, transferInfoFrame.RectTransform, Anchor.CenterRight), null)
itemTransferInfoBlock = new GUITextBlock(new RectTransform(Vector2.One, transferInfoFrame.RectTransform, Anchor.CenterRight), null)
{
TextAlignment = Alignment.CenterRight,
Visible = false
@@ -412,7 +411,7 @@ namespace Barotrauma
}
else
{
submarineDisplays[i].submarineFee.Text = currentSubText;
submarineDisplays[i].submarineFee.Text = selectedSubText;
}
}
@@ -607,35 +606,49 @@ namespace Barotrauma
UpdateItemTransferInfoFrame();
}
private bool ForceItemTransfer()
{
if (selectedSubmarine == null) { return false; }
return !selectedSubmarine.IsManuallyOutfitted && !GameMain.GameSession.IsSubmarineOwned(selectedSubmarine);
}
private bool IsSelectedSubCurrentSub => Submarine.MainSub?.Info?.Name == selectedSubmarine?.Name;
private void UpdateItemTransferInfoFrame()
{
if (selectedSubmarine != null)
{
var pendingSub = GameMain.GameSession?.Campaign?.PendingSubmarineSwitch;
if (Submarine.MainSub?.Info?.Name == selectedSubmarine.Name && pendingSub == null)
if (IsSelectedSubCurrentSub)
{
TransferItemsOnSwitch = false;
transferItemsTickBox.Visible = false;
itemTransferReminderBlock.Visible = false;
itemTransferInfoBlock.Visible = confirmButton.Enabled;
itemTransferInfoBlock.Text = TextManager.Get("switchingbacktocurrentsub");
}
else if (pendingSub?.Name == selectedSubmarine.Name)
else if (ForceItemTransfer())
{
TransferItemsOnSwitch = true;
transferItemsTickBox.Visible = false;
itemTransferInfoBlock.Visible = true;
itemTransferInfoBlock.Text = TransferItemsOnSwitch ? TextManager.Get("itemtransferenabledreminder") : TextManager.Get("itemtransferdisabledreminder");
}
else if (GameMain.GameSession?.Campaign?.PendingSubmarineSwitch?.Name == selectedSubmarine.Name)
{
transferItemsTickBox.Visible = false;
itemTransferReminderBlock.Text = GameMain.GameSession.Campaign.TransferItemsOnSubSwitch ?
TextManager.Get("itemtransferenabledreminder") :
TextManager.Get("itemtransferdisabledreminder");
itemTransferReminderBlock.Visible = true;
itemTransferInfoBlock.Visible = true;
itemTransferInfoBlock.Text = GameMain.GameSession.Campaign.TransferItemsOnSubSwitch ? TextManager.Get("itemtransferenabledreminder") : TextManager.Get("itemtransferdisabledreminder");
}
else
{
transferItemsTickBox.Selected = TransferItemsOnSwitch;
transferItemsTickBox.Visible = true;
itemTransferReminderBlock.Visible = false;
itemTransferInfoBlock.Visible = false;
}
}
else
{
transferItemsTickBox.Visible = false;
itemTransferReminderBlock.Visible = false;
itemTransferInfoBlock.Visible = false;
}
}
@@ -710,6 +723,40 @@ namespace Barotrauma
}
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
{
if (!TransferItemsOnSwitch && !IsSelectedSubCurrentSub)
{
if (selectedSubmarine.NoItems)
{
return ShowConfirmationPopup(TextManager.Get("noitemsheader"), TextManager.Get("noitemswarning"));
}
if (selectedSubmarine.LowFuel)
{
return ShowConfirmationPopup(TextManager.Get("lowfuelheader"), TextManager.Get("lowfuelwarning"));
}
}
return Confirm();
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = msgBox.Close;
bool ShowConfirmationPopup(LocalizedString header, LocalizedString textBody)
{
msgBox.Close();
var extraConfirmationBox = new GUIMessageBox(header, textBody, new LocalizedString[2] { TextManager.Get("ok"), TextManager.Get("cancel") });
extraConfirmationBox.Buttons[0].OnClicked = (b, o) => Confirm();
extraConfirmationBox.Buttons[1].OnClicked = (b, o) =>
{
selectedSubmarine = CurrentOrPendingSubmarine();
RefreshSubmarineDisplay(true);
return true;
};
extraConfirmationBox.Buttons[0].OnClicked += extraConfirmationBox.Close;
extraConfirmationBox.Buttons[1].OnClicked += extraConfirmationBox.Close;
return true;
}
bool Confirm()
{
if (GameMain.Client == null)
{
@@ -721,9 +768,7 @@ namespace Barotrauma
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, TransferItemsOnSwitch, Networking.VoteType.SwitchSub);
}
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = msgBox.Close;
}
}
private void ShowBuyPrompt(bool purchaseOnly)
@@ -792,7 +837,16 @@ namespace Barotrauma
private LocalizedString GetItemTransferText()
{
return "\n\n" + TextManager.Get(TransferItemsOnSwitch ? "itemswillbetransferred" : "itemswontbetransferred");
if (Submarine.MainSub?.Info?.Name == selectedSubmarine.Name)
{
return $"\n\n{TextManager.Get("switchingbacktocurrentsub")}";
}
var s = "\n\n" + TextManager.Get(TransferItemsOnSwitch ? "itemswillbetransferred" : "itemswontbetransferred");
if (!ForceItemTransfer())
{
s += $" {TextManager.Get("toggleitemtransferprompt")}";
}
return s;
}
}
}

View File

@@ -1885,6 +1885,7 @@ namespace Barotrauma
{
IgnoreLayoutGroups = true
};
newCharacterBox.TextBlock.AutoScaleHorizontal = true;
newCharacterBox.OnClicked = (button, o) =>
{

View File

@@ -107,10 +107,11 @@ namespace Barotrauma
CreateUI(upgradeFrame);
if (Campaign == null) { return; }
Campaign.UpgradeManager.OnUpgradesChanged += RequestRefresh;
Campaign.CargoManager.OnPurchasedItemsChanged += RequestRefresh;
Campaign.CargoManager.OnSoldItemsChanged += RequestRefresh;
Campaign.OnMoneyChanged.RegisterOverwriteExisting(nameof(UpgradeStore).ToIdentifier(), e => { RequestRefresh(); } );
Identifier eventId = new Identifier(nameof(UpgradeStore));
Campaign.UpgradeManager.OnUpgradesChanged?.RegisterOverwriteExisting(eventId, _ => RequestRefresh());
Campaign.CargoManager.OnPurchasedItemsChanged.RegisterOverwriteExisting(eventId, _ => RequestRefresh());
Campaign.CargoManager.OnSoldItemsChanged.RegisterOverwriteExisting(eventId, _ => RequestRefresh());
Campaign.OnMoneyChanged.RegisterOverwriteExisting(eventId, _ => RequestRefresh());
}
public void RequestRefresh()

View File

@@ -1109,27 +1109,6 @@ namespace Barotrauma
GUIMessageBox.CloseAll();
MainMenuScreen.Select();
GameSession = null;
}
public void ShowCampaignDisclaimer(Action onContinue = null)
{
var msgBox = new GUIMessageBox(TextManager.Get("CampaignDisclaimerTitle"), TextManager.Get("CampaignDisclaimerText"),
new LocalizedString[] { TextManager.Get("CampaignRoadMapTitle"), TextManager.Get("OK") });
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
{
ShowOpenUrlInWebBrowserPrompt("https://trello.com/b/hBXI8ltN/barotrauma-roadmap-known-issues");
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += (_, __) => { onContinue?.Invoke(); return true; };
var config = GameSettings.CurrentConfig;
config.CampaignDisclaimerShown = true;
GameSettings.SetCurrentConfig(config);
GameSettings.SaveCurrentConfig();
}
public void ShowEditorDisclaimer()

View File

@@ -52,7 +52,7 @@ namespace Barotrauma
{
ItemsInBuyCrate.Add(entry.Key, entry.Value);
}
OnItemsInBuyCrateChanged?.Invoke();
OnItemsInBuyCrateChanged?.Invoke(this);
}
public void SetItemsInSubSellCrate(Dictionary<Identifier, List<PurchasedItem>> items)
@@ -62,7 +62,7 @@ namespace Barotrauma
{
ItemsInSellFromSubCrate.Add(entry.Key, entry.Value);
}
OnItemsInSellFromSubCrateChanged?.Invoke();
OnItemsInSellFromSubCrateChanged?.Invoke(this);
}
public void SetSoldItems(Dictionary<Identifier, List<SoldItem>> items)
@@ -97,7 +97,7 @@ namespace Barotrauma
soldEntityMatch.Status = SoldEntity.SellStatus.Confirmed;
}
}
OnSoldItemsChanged?.Invoke();
OnSoldItemsChanged?.Invoke(this);
static bool Match(SoldItem soldItem, SoldEntity soldEntity, bool matchId)
{
@@ -122,7 +122,7 @@ namespace Barotrauma
{
GetSellCrateItems(storeIdentifier, create: true).Add(new PurchasedItem(itemPrefab, changeInQuantity));
}
OnItemsInSellCrateChanged?.Invoke();
OnItemsInSellCrateChanged?.Invoke(this);
}
public void SellItems(Identifier storeIdentifier, List<PurchasedItem> itemsToSell, Store.StoreTab sellingMode)
@@ -199,7 +199,7 @@ namespace Barotrauma
}
}
}
OnSoldItemsChanged?.Invoke();
OnSoldItemsChanged?.Invoke(this);
}
public void ClearSoldItemsProjSpecific()

View File

@@ -326,6 +326,47 @@ namespace Barotrauma
ReadyCheckButton?.AddToGUIUpdateList();
}
protected void TryEndRoundWithFuelCheck(Action onConfirm, Action onReturnToMapScreen)
{
Submarine.MainSub.CheckFuel();
SubmarineInfo nextSub = PendingSubmarineSwitch ?? Submarine.MainSub.Info;
if (Level.IsLoadedFriendlyOutpost && nextSub.LowFuel && CargoManager.PurchasedItems.None(i => i.Value.Any(pi => pi.ItemPrefab.Tags.Contains("reactorfuel"))))
{
var extraConfirmationBox =
new GUIMessageBox(TextManager.Get("lowfuelheader"),
TextManager.Get("lowfuelwarning"),
new LocalizedString[2] { TextManager.Get("ok"), TextManager.Get("cancel") });
extraConfirmationBox.Buttons[0].OnClicked = (b, o) => { Confirm(); return true; };
extraConfirmationBox.Buttons[0].OnClicked += extraConfirmationBox.Close;
extraConfirmationBox.Buttons[1].OnClicked = extraConfirmationBox.Close;
}
else
{
Confirm();
}
void Confirm()
{
var availableTransition = GetAvailableTransition(out _, out _);
if (Character.Controlled != null &&
availableTransition == TransitionType.ReturnToPreviousLocation &&
Character.Controlled?.Submarine == Level.Loaded?.StartOutpost)
{
onConfirm();
}
else if (Character.Controlled != null &&
availableTransition == TransitionType.ProgressToNextLocation &&
Character.Controlled?.Submarine == Level.Loaded?.EndOutpost)
{
onConfirm();
}
else
{
onReturnToMapScreen();
}
}
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);

View File

@@ -137,25 +137,14 @@ namespace Barotrauma
},
OnClicked = (btn, userdata) =>
{
var availableTransition = GetAvailableTransition(out _, out _);
if (Character.Controlled != null &&
availableTransition == TransitionType.ReturnToPreviousLocation &&
Character.Controlled?.Submarine == Level.Loaded?.StartOutpost)
{
GameMain.Client.RequestStartRound();
}
else if (Character.Controlled != null &&
availableTransition == TransitionType.ProgressToNextLocation &&
Character.Controlled?.Submarine == Level.Loaded?.EndOutpost)
{
GameMain.Client.RequestStartRound();
}
else
{
ShowCampaignUI = true;
if (CampaignUI == null) { InitCampaignUI(); }
CampaignUI.SelectTab(InteractionType.Map);
}
TryEndRoundWithFuelCheck(
onConfirm: () => GameMain.Client.RequestStartRound(),
onReturnToMapScreen: () =>
{
ShowCampaignUI = true;
if (CampaignUI == null) { InitCampaignUI(); }
CampaignUI.SelectTab(InteractionType.Map);
});
return true;
}
};

View File

@@ -184,24 +184,9 @@ namespace Barotrauma
},
OnClicked = (btn, userdata) =>
{
var availableTransition = GetAvailableTransition(out _, out _);
if (Character.Controlled != null &&
availableTransition == TransitionType.ReturnToPreviousLocation &&
Character.Controlled?.Submarine == Level.Loaded?.StartOutpost)
{
TryEndRound();
}
else if (Character.Controlled != null &&
availableTransition == TransitionType.ProgressToNextLocation &&
Character.Controlled?.Submarine == Level.Loaded?.EndOutpost)
{
TryEndRound();
}
else
{
ShowCampaignUI = true;
CampaignUI.SelectTab(InteractionType.Map);
}
TryEndRoundWithFuelCheck(
onConfirm: () => TryEndRound(),
onReturnToMapScreen: () => { ShowCampaignUI = true; CampaignUI.SelectTab(InteractionType.Map); });
return true;
}
};

View File

@@ -251,7 +251,7 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(2.0f);
}*/
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Medical supplies objective
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), "None"); // Medical supplies objective
do
{

View File

@@ -405,13 +405,13 @@ namespace Barotrauma.Items.Components
float newVolume;
try
{
newVolume = Math.Min(property.GetFloatValue(this), 1.0f);
newVolume = property.GetFloatValue(this);
}
catch
{
return 0.0f;
}
newVolume *= sound.VolumeMultiplier;
newVolume = Math.Min(newVolume * sound.VolumeMultiplier, 1.0f);
if (!MathUtils.IsValid(newVolume))
{

View File

@@ -89,7 +89,8 @@ namespace Barotrauma.Items.Components
if (Light?.LightSprite != null && item.Prefab.CanSpriteFlipX && item.body == null)
{
Light.LightSpriteEffect = Light.LightSpriteEffect == SpriteEffects.None ?
SpriteEffects.FlipHorizontally : SpriteEffects.None;
SpriteEffects.FlipHorizontally : SpriteEffects.None;
SetLightSourceTransformProjSpecific();
}
}

View File

@@ -985,7 +985,8 @@ namespace Barotrauma.Items.Components
missionIndex++;
}
if (AllowUsingMineralScanner && useMineralScanner && CurrentMode == Mode.Active && MineralClusters != null)
if (AllowUsingMineralScanner && useMineralScanner && CurrentMode == Mode.Active && MineralClusters != null &&
(item.CurrentHull == null || !DetectSubmarineWalls))
{
foreach (var c in MineralClusters)
{

View File

@@ -1,11 +1,9 @@
using Barotrauma.Networking;
using Barotrauma.Particles;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{

View File

@@ -10,22 +10,18 @@ namespace Barotrauma.Items.Components
{
int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100);
if (roundedValue == 0) { return; }
string colorStr = XMLExtensions.ColorToString(GUIStyle.Green);
string colorStr = XMLExtensions.ToStringHex(GUIStyle.Green);
LocalizedString afflictionName =
AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier == afflictionIdentifier)?.Name ??
TextManager.Get($"afflictiontype.{afflictionIdentifier}").Fallback(afflictionIdentifier.Value);
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {afflictionName}";
if (!description.IsNullOrWhiteSpace()) { description += '\n'; }
description += $" ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {afflictionName}";
}
public override void AddTooltipInfo(ref LocalizedString name, ref LocalizedString description)
{
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f) || !MathUtils.NearlyEqual(d.ProbabilityMultiplier, 1f)) || SkillModifiers.Any())
{
description += "\n";
}
if (damageModifiers.Any())
{
foreach (DamageModifier damageModifier in damageModifiers)
@@ -49,10 +45,11 @@ namespace Barotrauma.Items.Components
{
foreach (var skillModifier in SkillModifiers)
{
string colorStr = XMLExtensions.ColorToString(GUIStyle.Green);
string colorStr = XMLExtensions.ToStringHex(GUIStyle.Green);
int roundedValue = (int)Math.Round(skillModifier.Value);
if (roundedValue == 0) { continue; }
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("+0;-#")}‖color:end‖ {TextManager.Get($"SkillName.{skillModifier.Key}").Fallback(skillModifier.Key.Value)}";
if (!description.IsNullOrWhiteSpace()) { description += '\n'; }
description += $" ‖color:{colorStr}‖{roundedValue.ToString("+0;-#")}‖color:end‖ {TextManager.Get($"SkillName.{skillModifier.Key}").Fallback(skillModifier.Key.Value)}";
}
}
}

View File

@@ -292,7 +292,9 @@ namespace Barotrauma
}
else
{
description = TextManager.GetWithVariables("IDCardNameJob", ("[name]", idName, FormatCapitals.No), ("[job]", idJob, FormatCapitals.Yes));
description = TextManager.GetWithVariables("IDCardNameJob",
("[name]", idName, FormatCapitals.No),
("[job]", TextManager.Get("jobname." + idJob).Fallback(idJob), FormatCapitals.Yes));
}
if (!string.IsNullOrEmpty(item.Description))
{
@@ -1582,7 +1584,7 @@ namespace Barotrauma
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
}
if (itemContainer != null && itemContainer.ShowContainedStateIndicator)
if (itemContainer != null && itemContainer.ShowContainedStateIndicator && itemContainer.Capacity > 0)
{
float containedState = 0.0f;
if (itemContainer.ShowConditionInContainedStateIndicator)

View File

@@ -149,51 +149,18 @@ namespace Barotrauma
pos.X += Math.Sign(flowForce.X);
pos.Y = MathHelper.Clamp(Rand.Range(higherSurface, lowerSurface), rect.Y - rect.Height, rect.Y);
}
else
if (flowTargetHull != null)
{
pos.Y += Math.Sign(flowForce.Y) * rect.Height / 2.0f;
pos.X = MathHelper.Clamp(pos.X, flowTargetHull.Rect.X + 1, flowTargetHull.Rect.Right - 1);
pos.Y = MathHelper.Clamp(pos.Y, flowTargetHull.Rect.Y - flowTargetHull.Rect.Height + 1, flowTargetHull.Rect.Y - 1);
}
//spawn less particles when there's already a large number of them
float particleAmountMultiplier = 1.0f - GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles;
particleAmountMultiplier *= particleAmountMultiplier;
//light dripping
if (open < 0.2f && LerpedFlowForce.LengthSquared() > 100.0f)
{
particleTimer += deltaTime;
float particlesPerSec = open * 100.0f * particleAmountMultiplier;
float emitInterval = 1.0f / particlesPerSec;
while (particleTimer > emitInterval)
{
Vector2 velocity = flowForce;
if (!IsHorizontal)
{
velocity.X = Rand.Range(-500.0f, 500.0f) * open;
}
else
{
velocity.X *= Rand.Range(1.0f, 3.0f);
}
if (flowTargetHull.WaterVolume < flowTargetHull.Volume)
{
GameMain.ParticleManager.CreateParticle(
Rand.Range(0.0f, open) < 0.05f ? "waterdrop" : "watersplash",
(Submarine == null ? pos : pos + Submarine.Position),
velocity, 0, flowTargetHull);
}
GameMain.ParticleManager.CreateParticle(
"bubbles",
(Submarine == null ? pos : pos + Submarine.Position),
velocity, 0, flowTargetHull);
particleTimer -= emitInterval;
}
}
//heavy flow -> strong waterfall type of particles
else if (LerpedFlowForce.LengthSquared() > 20000.0f)
if (LerpedFlowForce.LengthSquared() > 20000.0f)
{
particleTimer += deltaTime;
if (IsHorizontal)
@@ -218,6 +185,10 @@ namespace Barotrauma
if (particle.CurrentHull == null) { GameMain.ParticleManager.RemoveParticle(particle); }
particle.Size *= Math.Min(Math.Abs(flowForce.X / 500.0f), 5.0f);
}
if (GapSize() <= Structure.WallSectionSize || !IsRoomToRoom)
{
CreateWaterSpatter();
}
}
if (Math.Abs(flowForce.X) > 300.0f && flowTargetHull.WaterVolume > flowTargetHull.Volume * 0.1f)
@@ -245,7 +216,7 @@ namespace Barotrauma
{
if (Math.Sign(flowTargetHull.Rect.Y - rect.Y) != Math.Sign(lerpedFlowForce.Y)) { return; }
float particlesPerSec = Math.Max(open * rect.Width * 0.3f * particleAmountMultiplier, 20.0f);
float particlesPerSec = Math.Max(open * rect.Width * 0.5f * particleAmountMultiplier, 10.0f);
float emitInterval = 1.0f / particlesPerSec;
while (particleTimer > emitInterval)
{
@@ -263,7 +234,11 @@ namespace Barotrauma
if (splash != null)
{
if (splash.CurrentHull == null) { GameMain.ParticleManager.RemoveParticle(splash); }
splash.Size *= MathHelper.Clamp(rect.Width / 50.0f, 1.5f, 4.0f);
splash.Size *= MathHelper.Clamp(rect.Width / 50.0f, 1.5f, 4.0f);
}
if (GapSize() <= Structure.WallSectionSize || !IsRoomToRoom)
{
CreateWaterSpatter();
}
}
if (Math.Abs(flowForce.Y) > 190.0f && Rand.Range(0.0f, 1.0f) < 0.3f && flowTargetHull.WaterVolume > flowTargetHull.Volume * 0.1f)
@@ -277,10 +252,77 @@ namespace Barotrauma
}
}
}
//light dripping
else if (LerpedFlowForce.LengthSquared() > 100.0f &&
/*no dripping from large gaps between rooms (looks bad)*/
((GapSize() <= Structure.WallSectionSize) || !IsRoomToRoom))
{
particleTimer += deltaTime;
float particlesPerSec = open * 100.0f * particleAmountMultiplier;
float emitInterval = 1.0f / particlesPerSec;
while (particleTimer > emitInterval)
{
Vector2 velocity = flowForce;
if (!IsHorizontal)
{
velocity.X = Rand.Range(-100.0f, 100.0f) * open;
}
else
{
velocity.X *= Rand.Range(1.0f, 3.0f);
}
if (flowTargetHull.WaterVolume < flowTargetHull.Volume)
{
GameMain.ParticleManager.CreateParticle(
Rand.Range(0.0f, open) < 0.05f ? "waterdrop" : "watersplash",
Submarine == null ? pos : pos + Submarine.Position,
velocity, 0, flowTargetHull);
CreateWaterSpatter();
}
GameMain.ParticleManager.CreateParticle(
"bubbles",
(Submarine == null ? pos : pos + Submarine.Position),
velocity, 0, flowTargetHull);
particleTimer -= emitInterval;
}
}
else
{
particleTimer = 0.0f;
}
void CreateWaterSpatter()
{
Vector2 spatterPos = pos;
float rotation;
if (IsHorizontal)
{
rotation = LerpedFlowForce.X > 0 ? 0 : MathHelper.Pi;
spatterPos.Y = rect.Y - rect.Height / 2;
}
else
{
rotation = LerpedFlowForce.Y > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
spatterPos.X = rect.Center.X;
}
var spatter = GameMain.ParticleManager.CreateParticle(
"waterspatter",
Submarine == null ? spatterPos : spatterPos + Submarine.Position,
Vector2.Zero, rotation, flowTargetHull);
if (spatter != null)
{
if (spatter.CurrentHull == null) { GameMain.ParticleManager.RemoveParticle(spatter); }
spatter.Size *= MathHelper.Clamp(LerpedFlowForce.Length() / 200.0f, 0.5f, 1.0f);
}
}
float GapSize()
{
return IsHorizontal ? rect.Height : rect.Width;
}
}
}
}

View File

@@ -254,7 +254,7 @@ namespace Barotrauma.Lights
}
//remove some lights with a light volume if there's too many of them
if (activeLightsWithLightVolume.Count > GameSettings.CurrentConfig.Graphics.VisibleLightLimit)
if (activeLightsWithLightVolume.Count > GameSettings.CurrentConfig.Graphics.VisibleLightLimit && Screen.Selected is { IsEditor: false })
{
for (int i = GameSettings.CurrentConfig.Graphics.VisibleLightLimit; i < activeLightsWithLightVolume.Count; i++)
{

View File

@@ -52,7 +52,7 @@ namespace Barotrauma.Lights
[Serialize(0f, IsPropertySaveable.Yes), Editable(MinValueFloat = -360, MaxValueFloat = 360, ValueStep = 1, DecimalCount = 0)]
public float Rotation { get; set; }
public Vector2 GetOffset() => Vector2.Transform(Offset, Matrix.CreateRotationZ(Rotation));
public Vector2 GetOffset() => Vector2.Transform(Offset, Matrix.CreateRotationZ(MathHelper.ToRadians(Rotation)));
private float flicker;
[Editable, Serialize(0.0f, IsPropertySaveable.No, description: "How heavily the light flickers. 0 = no flickering, 1 = the light will alternate between completely dark and full brightness.")]

View File

@@ -110,7 +110,9 @@ namespace Barotrauma
{
noiseOverlay ??= new Sprite("Content/UI/noise.png", Vector2.Zero);
OnLocationChanged = LocationChanged;
OnLocationChanged.RegisterOverwriteExisting(
"Map.InitProjSpecific".ToIdentifier(),
(locationChangeInfo) => LocationChanged(locationChangeInfo.PrevLocation, locationChangeInfo.NewLocation));
borders = new Rectangle(
(int)Locations.Min(l => l.MapPosition.X),
@@ -447,7 +449,7 @@ namespace Barotrauma
Level.Loaded.DebugSetEndLocation(null);
CurrentLocation.Discover();
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
OnLocationChanged?.Invoke(new LocationChangeInfo(prevLocation, CurrentLocation));
SelectLocation(-1);
if (GameMain.Client == null)
{

View File

@@ -88,6 +88,11 @@ namespace Barotrauma
prevCullTime = 0;
}
public static void ForceRemoveFromVisibleEntities(MapEntity entity)
{
visibleEntities?.Remove(entity);
}
public static void Draw(SpriteBatch spriteBatch, bool editing = false)
{
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList;

View File

@@ -1845,8 +1845,11 @@ namespace Barotrauma.Networking
GameMain.GameScreen.Select();
// TODO: Re-enable the server message once it's been edited and translated
//AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
string message = "ServerMessage.HowToCommunicate" +
$"~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ActiveChat)}" +
$"~[pttbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Voice)}" +
$"~[switchbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleChatMode)}";
AddChatMessage(message, ChatMessageType.Server);
yield return CoroutineStatus.Success;
}

View File

@@ -275,7 +275,7 @@ namespace Barotrauma
{
GUILayoutGroup inputContainer = CreateSettingBase(parent, description, tooltip, horizontalSize: 0.55f, verticalSize: verticalSize);
GUIButton minusButton = new GUIButton(new RectTransform(Vector2.One, inputContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton", textAlignment: Alignment.Center) { UserData = -1 };
GUIButton minusButton = new GUIButton(new RectTransform(Vector2.One, inputContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIButtonToggleLeft", textAlignment: Alignment.Center) { UserData = -1 };
GUIFrame inputFrame = new GUIFrame(new RectTransform(Vector2.One, inputContainer.RectTransform), style: null);
GUINumberInput numberInput = new GUINumberInput(new RectTransform(Vector2.One, inputFrame.RectTransform, Anchor.Center), NumberType.Int, textAlignment: Alignment.Center, style: "GUITextBox", hidePlusMinusButtons: true)
{
@@ -290,7 +290,7 @@ namespace Barotrauma
CanBeFocused = false
};
GUIButton plusButton = new GUIButton(new RectTransform(Vector2.One, inputContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center) { UserData = 1 };
GUIButton plusButton = new GUIButton(new RectTransform(Vector2.One, inputContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIButtonToggleRight", textAlignment: Alignment.Center) { UserData = 1 };
minusButton.OnClicked = plusButton.OnClicked = ChangeValue;

View File

@@ -235,13 +235,6 @@ namespace Barotrauma
}
};
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(5) }, style: "GUINotificationButton")
{
IgnoreLayoutGroups = true,
OnClicked = (btn, userdata) => { GameMain.Instance.ShowCampaignDisclaimer(); return true; }
};
disclaimerBtn.RectTransform.MaxSize = new Point((int)(30 * GUI.Scale));
columnContainer.Recalculate();
leftColumn.Recalculate();
rightColumn.Recalculate();

View File

@@ -57,8 +57,8 @@ namespace Barotrauma
CreateUI(container);
campaign.Map.OnLocationSelected += SelectLocation;
campaign.Map.OnMissionsSelected += (connection, missions) =>
campaign.Map.OnLocationSelected = SelectLocation;
campaign.Map.OnMissionsSelected = (connection, missions) =>
{
if (missionList?.Content != null)
{

View File

@@ -534,12 +534,6 @@ namespace Barotrauma
ShowTutorialSkipWarning(Tab.NewGame);
return true;
}
if (!GameSettings.CurrentConfig.CampaignDisclaimerShown)
{
selectedTab = Tab.Empty;
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.NewGame); });
return true;
}
campaignSetupUI.RandomizeCrew();
campaignSetupUI.SetPage(0);
campaignSetupUI.CreateDefaultSaveName();
@@ -559,12 +553,6 @@ namespace Barotrauma
ShowTutorialSkipWarning(Tab.JoinServer);
return true;
}
if (!GameSettings.CurrentConfig.CampaignDisclaimerShown)
{
selectedTab = Tab.Empty;
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.JoinServer); });
return true;
}
GameMain.ServerListScreen.Select();
break;
case Tab.HostServer:
@@ -574,13 +562,6 @@ namespace Barotrauma
ShowTutorialSkipWarning(tab);
return true;
}
if (!GameSettings.CurrentConfig.CampaignDisclaimerShown)
{
selectedTab = Tab.Empty;
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.HostServer); });
return true;
}
serverExecutableDropdown.ListBox.Content.Children.ToArray()
.Where(c => c.UserData is ServerExecutableFile f && !ContentPackageManager.EnabledPackages.All.Contains(f.ContentPackage))
.ForEach(serverExecutableDropdown.ListBox.RemoveChild);
@@ -611,12 +592,6 @@ namespace Barotrauma
}
break;
case Tab.Tutorials:
if (!GameSettings.CurrentConfig.CampaignDisclaimerShown)
{
selectedTab = Tab.Empty;
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.Tutorials); });
return true;
}
UpdateTutorialList();
break;
case Tab.CharacterEditor:

View File

@@ -1814,7 +1814,7 @@ namespace Barotrauma
{
if (Submarine.GetLightCount() > MaxLights)
{
new GUIMessageBox(TextManager.Get("error"), TextManager.GetWithVariable("subeditor.lightcounterror", "[max]", MaxShadowCastingLights.ToString()));
new GUIMessageBox(TextManager.Get("error"), TextManager.GetWithVariable("subeditor.lightcounterror", "[max]", MaxLights.ToString()));
return false;
}
@@ -2522,6 +2522,27 @@ namespace Barotrauma
}
};
var outFittingArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), subSettingsContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
AbsoluteSpacing = 5
};
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), outFittingArea.RectTransform),
TextManager.Get("ManuallyOutfitted"), textAlignment: Alignment.CenterLeft, wrap: true, font: GUIStyle.SmallFont)
{
ToolTip = TextManager.Get("manuallyoutfittedtooltip")
};
new GUITickBox(new RectTransform((0.4f, 1.0f), outFittingArea.RectTransform), "")
{
ToolTip = TextManager.Get("manuallyoutfittedtooltip"),
Selected = MainSub.Info.IsManuallyOutfitted,
OnSelected = box =>
{
MainSub.Info.IsManuallyOutfitted = box.Selected;
return true;
}
};
if (MainSub != null)
{
int min = MainSub.Info.RecommendedCrewSizeMin;
@@ -2824,7 +2845,7 @@ namespace Barotrauma
};
var saveButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonArea.RectTransform, Anchor.BottomRight),
TextManager.Get("SaveSubButton"))
TextManager.Get("SaveSubButton").Fallback(TextManager.Get("save")))
{
OnClicked = (button, o) => SaveSub(packageToSaveInList.SelectedData as ContentPackage)
};
@@ -3502,8 +3523,11 @@ namespace Barotrauma
modProject.RemoveFile(modProject.Files.First(f => ContentPath.FromRaw(subPackage, f.Path) == sub.FilePath));
modProject.Save(subPackage.Path);
ReloadModifiedPackage(subPackage);
}
if (MainSub?.Info != null && MainSub.Info.FilePath == sub.FilePath)
{
MainSub.Info.FilePath = null;
}
}
sub.Dispose();
CreateLoadScreen();
}
@@ -5036,8 +5060,8 @@ 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;
saveAssemblyFrame.Visible = MapEntity.SelectedList.Count > 0 && !WiringMode;
snapToGridFrame.Visible = MapEntity.SelectedList.Count > 0 && !WiringMode;
var offset = cam.WorldView.Top - cam.ScreenToWorld(new Vector2(0, GameMain.GraphicsHeight - EntityMenu.Rect.Top)).Y;

View File

@@ -629,16 +629,18 @@ namespace Barotrauma
bool isFlagsAttribute = value.GetType().IsDefined(typeof(FlagsAttribute), false);
bool hasNoneOption = false;
foreach (object enumValue in Enum.GetValues(value.GetType()))
{
if (isFlagsAttribute && !MathHelper.IsPowerOfTwo((int)enumValue)) { continue; }
hasNoneOption |= (int)enumValue == 0;
enumDropDown.AddItem(enumValue.ToString(), enumValue);
if (((int)enumValue != 0 || (int)value == 0) && ((Enum)value).HasFlag((Enum)enumValue))
{
enumDropDown.SelectItem(enumValue);
}
}
enumDropDown.MustSelectAtLeastOne = !hasNoneOption;
enumDropDown.OnSelected += (selected, val) =>
{
if (SetPropertyValue(property, entity, string.Join(", ", enumDropDown.SelectedDataMultiple.Select(d => d.ToString()))))
@@ -1441,7 +1443,21 @@ namespace Barotrauma
if (component.GetType() == parentObject.GetType() && component != parentObject)
{
SafeAdd(component, property);
property.PropertyInfo.SetValue(component, value);
if (value is string stringValue && Enum.TryParse(property.PropertyType, stringValue, out var enumValue))
{
property.PropertyInfo.SetValue(component, enumValue);
}
else
{
try
{
property.PropertyInfo.SetValue(component, value);
}
catch (ArgumentException e)
{
DebugConsole.ThrowError($"Failed to set the value of the property \"{property.Name}\" to {value?.ToString() ?? "null"}", e);
}
}
}
}
break;

View File

@@ -45,6 +45,20 @@ namespace Barotrauma
Instance = new SettingsMenu(mainParent);
return Instance;
}
public void Recreate()
{
if (GUI.SettingsMenuOpen)
{
GUI.SettingsMenuOpen = false;
GUI.SettingsMenuOpen = true;
}
else
{
Create(mainFrame.Parent.RectTransform);
Instance?.SelectTab(Tab.Controls);
}
}
private SettingsMenu(RectTransform mainParent)
{
@@ -653,7 +667,7 @@ namespace Barotrauma
{
unsavedConfig.InventoryKeyMap = GameSettings.Config.InventoryKeyMapping.GetDefault();
unsavedConfig.KeyMap = GameSettings.Config.KeyMapping.GetDefault();
Create(mainFrame.Parent.RectTransform);
Recreate();
Instance?.SelectTab(Tab.Controls);
return true;
}
@@ -761,7 +775,7 @@ namespace Barotrauma
private void CreateBottomButtons()
{
GUIButton cancelButton =
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: "Cancel")
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get("Cancel"))
{
OnClicked = (btn, obj) =>
{
@@ -770,7 +784,7 @@ namespace Barotrauma
}
};
GUIButton applyButton =
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: "Apply")
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), bottom.RectTransform), text: TextManager.Get("applysettingsbutton"))
{
OnClicked = (btn, obj) =>
{

View File

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

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.18.11.0</Version>
<Version>0.18.13.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.11.0</Version>
<Version>0.18.13.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.11.0</Version>
<Version>0.18.13.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.11.0</Version>
<Version>0.18.13.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.11.0</Version>
<Version>0.18.13.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -562,8 +562,10 @@ namespace Barotrauma
}
}
private List<int> severedJointIndices = new List<int>();
private void WriteStatus(IWriteMessage msg)
private readonly List<int> severedJointIndices = new List<int>();
/// <param name="forceAfflictionData">Normally full affliction data is not written for dead characters, this can be used to force them to be written</param>
private void WriteStatus(IWriteMessage msg, bool forceAfflictionData = false)
{
msg.Write(IsDead);
if (IsDead)
@@ -573,6 +575,11 @@ namespace Barotrauma
{
msg.Write(CauseOfDeath.Affliction.Identifier);
}
msg.Write(forceAfflictionData);
if (forceAfflictionData)
{
CharacterHealth.ServerWrite(msg);
}
}
else
{
@@ -689,7 +696,7 @@ namespace Barotrauma
if (msg.LengthBytes - initialMsgLength >= 255 && restrictMessageSize)
{
string errorMsg = $"Error when writing character spawn data: data exceeded 255 bytes (info: {infoLength}, orders: {ordersLength}, total: {msg.LengthBytes - initialMsgLength})";
string errorMsg = $"Error when writing character spawn data for \"{Name}\": data exceeded 255 bytes (info: {infoLength}, orders: {ordersLength}, total: {msg.LengthBytes - initialMsgLength})";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Character.WriteSpawnData:TooMuchData", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
@@ -701,13 +708,13 @@ namespace Barotrauma
int msgLengthBeforeStatus = msg.LengthBytes - initialMsgLength;
var tempBuffer = new ReadWriteMessage();
WriteStatus(tempBuffer);
WriteStatus(tempBuffer, forceAfflictionData: true);
if (msgLengthBeforeStatus + tempBuffer.LengthBytes >= 255 && restrictMessageSize)
{
msg.Write(false);
if (msgLengthBeforeStatus < 255)
{
string errorMsg = $"Error when writing character spawn data: status data caused the length of the message to exceed 255 bytes ({msgLengthBeforeStatus} + {tempBuffer.LengthBytes})";
string errorMsg = $"Error when writing character spawn data for \"{Name}\": status data caused the length of the message to exceed 255 bytes ({msgLengthBeforeStatus} + {tempBuffer.LengthBytes})";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Character.WriteSpawnData:TooMuchDataForStatus", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
@@ -715,7 +722,7 @@ namespace Barotrauma
else
{
msg.Write(true);
WriteStatus(msg);
WriteStatus(msg, forceAfflictionData: true);
}
}

View File

@@ -77,7 +77,7 @@ namespace Barotrauma
campaign.GetWallet(client).Give(itemValue);
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
}
OnSoldItemsChanged?.Invoke();
OnSoldItemsChanged?.Invoke(this);
}
public void ClearSoldItemsProjSpecific()

View File

@@ -393,14 +393,17 @@ namespace Barotrauma
}
partial void InitProjSpecific()
{
CargoManager.OnItemsInBuyCrateChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.ItemsInBuyCrate); };
CargoManager.OnPurchasedItemsChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.PurchasedItems); };
CargoManager.OnSoldItemsChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.SoldItems); };
UpgradeManager.OnUpgradesChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.UpgradeManager); };
Map.OnLocationSelected += (loc, connection) => { IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions); };
Map.OnMissionsSelected += (loc, mission) => { IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions); };
Reputation.OnAnyReputationValueChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.Reputation); };
{
Identifier eventId = nameof(MultiPlayerCampaign).ToIdentifier();
CargoManager.OnItemsInBuyCrateChanged.RegisterOverwriteExisting(eventId, _ => IncrementLastUpdateIdForFlag(NetFlags.ItemsInBuyCrate));
CargoManager.OnPurchasedItemsChanged.RegisterOverwriteExisting(eventId, _ => IncrementLastUpdateIdForFlag(NetFlags.PurchasedItems));
CargoManager.OnSoldItemsChanged.RegisterOverwriteExisting(eventId, _ => IncrementLastUpdateIdForFlag(NetFlags.SoldItems));
UpgradeManager.OnUpgradesChanged.RegisterOverwriteExisting(eventId, _ => IncrementLastUpdateIdForFlag(NetFlags.UpgradeManager));
Reputation.OnAnyReputationValueChanged.RegisterOverwriteExisting(eventId, _ => IncrementLastUpdateIdForFlag(NetFlags.Reputation));
Map.OnLocationSelected = (loc, connection) => IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions);
Map.OnMissionsSelected = (loc, mission) => IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions);
//increment save ID so clients know they're lacking the most up-to-date save file
LastSaveID++;

View File

@@ -2409,17 +2409,20 @@ namespace Barotrauma.Networking
campaign?.CargoManager.InitPurchasedIDCards();
foreach (Submarine sub in Submarine.MainSubs)
if (campaign == null || campaign.IsFirstRound)
{
if (sub == null) { continue; }
List<PurchasedItem> spawnList = new List<PurchasedItem>();
foreach (KeyValuePair<ItemPrefab, int> kvp in serverSettings.ExtraCargo)
foreach (Submarine sub in Submarine.MainSubs)
{
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value, buyer: null));
}
if (sub == null) { continue; }
CargoManager.CreateItems(spawnList, sub, cargoManager: null);
List<PurchasedItem> spawnList = new List<PurchasedItem>();
foreach (KeyValuePair<ItemPrefab, int> kvp in serverSettings.ExtraCargo)
{
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value, buyer: null));
}
CargoManager.CreateItems(spawnList, sub, cargoManager: null);
}
}
TraitorManager = null;

View File

@@ -19,7 +19,8 @@ namespace Barotrauma.Networking
if (Sender != null && c.InGame)
{
msg.Write(Sender.ID);
}
}
msg.Write(false); //text color (no custom text colors for order messages)
msg.WritePadBits();
WriteOrder(msg);
}

View File

@@ -65,6 +65,8 @@ namespace Barotrauma.Steam
Steamworks.SteamServer.SetKey("allowspectating", server.ServerSettings.AllowSpectating.ToString());
Steamworks.SteamServer.SetKey("allowrespawn", server.ServerSettings.AllowRespawn.ToString());
Steamworks.SteamServer.SetKey("traitors", server.ServerSettings.TraitorsEnabled.ToString());
Steamworks.SteamServer.SetKey("friendlyfireenabled", server.ServerSettings.AllowFriendlyFire.ToString());
Steamworks.SteamServer.SetKey("karmaenabled", server.ServerSettings.KarmaEnabled.ToString());
Steamworks.SteamServer.SetKey("gamestarted", server.GameStarted.ToString());
Steamworks.SteamServer.SetKey("gamemode", server.ServerSettings.GameModeIdentifier.Value);
Steamworks.SteamServer.SetKey("playstyle", server.ServerSettings.PlayStyle.ToString());

View File

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

View File

@@ -308,6 +308,7 @@ namespace Barotrauma
}
}
}
if (targetSlot < 0) { return false; }
return targetInventory.TryPutItem(item, targetSlot, allowSwapping, allowCombine: false, Character);
}
else

View File

@@ -1297,6 +1297,7 @@ namespace Barotrauma
AIObjectiveCombat.CombatMode DetermineCombatMode(Character c, float cumulativeDamage = 0, bool isWitnessing = false)
{
if (!(c.AIController is HumanAIController humanAI)) { return AIObjectiveCombat.CombatMode.None; }
if (!IsFriendly(attacker))
{
if (c.Submarine == null)
@@ -1306,12 +1307,15 @@ namespace Barotrauma
}
if (!c.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
{
// Attacked from an unconnected submarine.
return c.SelectedConstruction?.GetComponent<Turret>() != null ? AIObjectiveCombat.CombatMode.None : AIObjectiveCombat.CombatMode.Retreat;
// Attacked from an unconnected submarine (pirate/pvp)
return
humanAI.ObjectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder.GetTarget() is Controller ?
AIObjectiveCombat.CombatMode.None : AIObjectiveCombat.CombatMode.Retreat;
}
return c.AIController is HumanAIController humanAI &&
(humanAI.ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() || humanAI.ObjectiveManager.Objectives.Any(o => o is AIObjectiveFightIntruders))
? AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Defensive;
return
humanAI.ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() ||
humanAI.ObjectiveManager.Objectives.Any(o => o is AIObjectiveFightIntruders) ?
AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Defensive;
}
else
{
@@ -1362,7 +1366,7 @@ namespace Barotrauma
}
else
{
if (c.AIController is HumanAIController humanAI && humanAI.ObjectiveManager.GetActiveObjective<AIObjectiveCombat>()?.Enemy == attacker)
if (humanAI.ObjectiveManager.GetActiveObjective<AIObjectiveCombat>()?.Enemy == attacker)
{
// Already targeting the attacker -> treat as a more serious threat.
cumulativeDamage *= 2;

View File

@@ -31,8 +31,9 @@ namespace Barotrauma
if (!pump.Item.IsInteractable(character)) { return false; }
if (pump.IsAutoControlled) { return false; }
if (pump.Item.ConditionPercentage <= 0) { return false; }
if (pump.Item.CurrentHull == null) { return false; }
if (pump.Item.CurrentHull.FireSources.Count > 0) { return false; }
if (character.Submarine != null)
if (character.Submarine != null && pump.Item.Submarine != null)
{
if (!character.Submarine.IsConnectedTo(pump.Item.Submarine)) { return false; }
}

View File

@@ -1030,21 +1030,30 @@ namespace Barotrauma
/// <param name="hasAi">Is the character controlled by AI.</param>
/// <param name="createNetworkEvent">Should clients receive a network event about the creation of this character?</param>
/// <param name="ragdoll">Ragdoll configuration file. If null, will select the default.</param>
public static Character Create(string speciesName, Vector2 position, string seed, CharacterInfo characterInfo = null, ushort id = Entity.NullEntityID, bool isRemotePlayer = false, bool hasAi = true, bool createNetworkEvent = true, RagdollParams ragdoll = null)
public static Character Create(string speciesName, Vector2 position, string seed, CharacterInfo characterInfo = null, ushort id = Entity.NullEntityID, bool isRemotePlayer = false, bool hasAi = true, bool createNetworkEvent = true, RagdollParams ragdoll = null, bool throwErrorIfNotFound = true)
{
if (speciesName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
{
speciesName = Path.GetFileNameWithoutExtension(speciesName);
}
return Create(speciesName.ToIdentifier(), position, seed, characterInfo, id, isRemotePlayer, hasAi, createNetworkEvent, ragdoll);
return Create(speciesName.ToIdentifier(), position, seed, characterInfo, id, isRemotePlayer, hasAi, createNetworkEvent, ragdoll, throwErrorIfNotFound);
}
public static Character Create(Identifier speciesName, Vector2 position, string seed, CharacterInfo characterInfo = null, ushort id = Entity.NullEntityID, bool isRemotePlayer = false, bool hasAi = true, bool createNetworkEvent = true, RagdollParams ragdoll = null)
public static Character Create(Identifier speciesName, Vector2 position, string seed, CharacterInfo characterInfo = null, ushort id = Entity.NullEntityID, bool isRemotePlayer = false, bool hasAi = true, bool createNetworkEvent = true, RagdollParams ragdoll = null, bool throwErrorIfNotFound = true)
{
var prefab = CharacterPrefab.FindBySpeciesName(speciesName);
if (prefab == null)
{
DebugConsole.ThrowError($"Failed to create character \"{speciesName}\". Matching prefab not found.\n" + Environment.StackTrace);
string errorMsg = $"Failed to create character \"{speciesName}\". Matching prefab not found.\n" + Environment.StackTrace;
if (throwErrorIfNotFound)
{
DebugConsole.ThrowError(errorMsg);
}
else
{
DebugConsole.AddWarning(errorMsg);
}
return null;
}
return Create(prefab, position, seed, characterInfo, id, isRemotePlayer, hasAi, createNetworkEvent, ragdoll);
@@ -1510,9 +1519,10 @@ namespace Barotrauma
if (skillIdentifier != null)
{
for (int i = 0; i < Inventory.Capacity; i++)
foreach (Item item in Inventory.AllItems)
{
if (Inventory.SlotTypes[i] != InvSlotType.Any && Inventory.GetItemAt(i)?.GetComponent<Wearable>() is Wearable wearable)
if (item?.GetComponent<Wearable>() is Wearable wearable &&
!Inventory.IsInLimbSlot(item, InvSlotType.Any))
{
if (wearable.SkillModifiers.TryGetValue(skillIdentifier, out float skillValue))
{

View File

@@ -1639,8 +1639,13 @@ namespace Barotrauma
private void RefreshHeadSprites()
{
HeadSprite = null;
AttachmentSprites = null;
_headSprite = null;
LoadHeadSprite();
#if CLIENT
CalculateHeadPosition(_headSprite);
#endif
attachmentSprites?.Clear();
LoadAttachmentSprites();
}
// This could maybe be a LookUp instead?

View File

@@ -809,8 +809,13 @@ namespace Barotrauma
if (!Character.GodMode)
{
UpdateLimbAfflictionOverlays();
UpdateSkinTint();
#if CLIENT
if (Character.IsVisible)
{
UpdateLimbAfflictionOverlays();
UpdateSkinTint();
}
#endif
CalculateVitality();
if (Vitality <= MinVitality)
@@ -820,6 +825,12 @@ namespace Barotrauma
}
}
public void ForceUpdateVisuals()
{
UpdateLimbAfflictionOverlays();
UpdateSkinTint();
}
private void UpdateDamageReductions(float deltaTime)
{
float healthRegen = Character.Params.Health.ConstantHealthRegeneration;

View File

@@ -532,7 +532,13 @@ namespace Barotrauma
}
}
Character createdCharacter = Character.Create(SpeciesName, pos, seed, characterInfo: null, isRemotePlayer: false, hasAi: true, createNetworkEvent: true);
Character createdCharacter = Character.Create(SpeciesName, pos, seed, characterInfo: null, isRemotePlayer: false, hasAi: true, createNetworkEvent: true, throwErrorIfNotFound: false);
if (createdCharacter == null)
{
disallowed = true;
return;
}
var eventManager = GameMain.GameSession.EventManager;
if (eventManager != null)
{

View File

@@ -28,6 +28,7 @@ namespace Barotrauma
var subs = sub.GetConnectedSubs().Where(s => s.TeamID == sub.TeamID);
CreateAndPlace(subs);
subs.ForEach(s => s.Info.InitialSuppliesSpawned = true);
sub.CheckFuel();
}
}

View File

@@ -147,12 +147,12 @@ namespace Barotrauma
private Location Location => campaign?.Map?.CurrentLocation;
public Action OnItemsInBuyCrateChanged;
public Action OnItemsInSellCrateChanged;
public Action OnItemsInSellFromSubCrateChanged;
public Action OnPurchasedItemsChanged;
public Action OnSoldItemsChanged;
public readonly NamedEvent<CargoManager> OnItemsInBuyCrateChanged = new NamedEvent<CargoManager>();
public readonly NamedEvent<CargoManager> OnItemsInSellCrateChanged = new NamedEvent<CargoManager>();
public readonly NamedEvent<CargoManager> OnItemsInSellFromSubCrateChanged = new NamedEvent<CargoManager>();
public readonly NamedEvent<CargoManager> OnPurchasedItemsChanged = new NamedEvent<CargoManager>();
public readonly NamedEvent<CargoManager> OnSoldItemsChanged = new NamedEvent<CargoManager>();
public CargoManager(CampaignMode campaign)
{
this.campaign = campaign;
@@ -215,19 +215,19 @@ namespace Barotrauma
public void ClearItemsInBuyCrate()
{
ItemsInBuyCrate.Clear();
OnItemsInBuyCrateChanged?.Invoke();
OnItemsInBuyCrateChanged?.Invoke(this);
}
public void ClearItemsInSellCrate()
{
ItemsInSellCrate.Clear();
OnItemsInSellCrateChanged?.Invoke();
OnItemsInSellCrateChanged?.Invoke(this);
}
public void ClearItemsInSellFromSubCrate()
{
ItemsInSellFromSubCrate.Clear();
OnItemsInSellFromSubCrateChanged?.Invoke();
OnItemsInSellFromSubCrateChanged?.Invoke(this);
}
public void SetPurchasedItems(Dictionary<Identifier, List<PurchasedItem>> purchasedItems)
@@ -238,7 +238,7 @@ namespace Barotrauma
{
PurchasedItems.Add(entry.Key, entry.Value);
}
OnPurchasedItemsChanged?.Invoke();
OnPurchasedItemsChanged?.Invoke(this);
}
public void ModifyItemQuantityInBuyCrate(Identifier storeIdentifier, ItemPrefab itemPrefab, int changeInQuantity, Client client = null)
@@ -255,7 +255,7 @@ namespace Barotrauma
{
GetBuyCrateItems(storeIdentifier, create: true).Add(new PurchasedItem(itemPrefab, changeInQuantity, client));
}
OnItemsInBuyCrateChanged?.Invoke();
OnItemsInBuyCrateChanged?.Invoke(this);
}
public void ModifyItemQuantityInSubSellCrate(Identifier storeIdentifier, ItemPrefab itemPrefab, int changeInQuantity, Client client = null)
@@ -272,7 +272,7 @@ namespace Barotrauma
{
GetSubCrateItems(storeIdentifier, create: true).Add(new PurchasedItem(itemPrefab, changeInQuantity, client));
}
OnItemsInSellFromSubCrateChanged?.Invoke();
OnItemsInSellFromSubCrateChanged?.Invoke(this);
}
#if SERVER
@@ -331,7 +331,7 @@ namespace Barotrauma
}
}
}
OnPurchasedItemsChanged?.Invoke();
OnPurchasedItemsChanged?.Invoke(this);
}
public Dictionary<ItemPrefab, int> GetBuyValuesAtCurrentLocation(Identifier storeIdentifier, IEnumerable<ItemPrefab> items)
@@ -378,7 +378,7 @@ namespace Barotrauma
}
CreateItems(items, Submarine.MainSub, this);
PurchasedItems.Clear();
OnPurchasedItemsChanged?.Invoke();
OnPurchasedItemsChanged?.Invoke(this);
}
private Dictionary<ItemPrefab, int> UndeterminedSoldEntities { get; } = new Dictionary<ItemPrefab, int>();

View File

@@ -39,8 +39,8 @@ namespace Barotrauma
float prevValue = Value;
Metadata.SetValue(metaDataIdentifier, Math.Clamp(value, MinReputation, MaxReputation));
OnReputationValueChanged?.Invoke();
OnAnyReputationValueChanged?.Invoke();
OnReputationValueChanged?.Invoke(this);
OnAnyReputationValueChanged?.Invoke(this);
#if CLIENT
int increase = (int)Value - (int)prevValue;
if (increase != 0 && Character.Controlled != null)
@@ -73,8 +73,8 @@ namespace Barotrauma
Value += reputationChange;
}
public Action OnReputationValueChanged;
public static Action OnAnyReputationValueChanged;
public readonly NamedEvent<Reputation> OnReputationValueChanged = new NamedEvent<Reputation>();
public static readonly NamedEvent<Reputation> OnAnyReputationValueChanged = new NamedEvent<Reputation>();
public readonly Faction Faction;
public readonly Location Location;

View File

@@ -1005,7 +1005,7 @@ namespace Barotrauma
}
}
public SubmarineInfo SwitchSubs()
public void SwitchSubs()
{
if (TransferItemsOnSubSwitch)
{
@@ -1013,7 +1013,6 @@ namespace Barotrauma
}
RefreshOwnedSubmarines();
PendingSubmarineSwitch = null;
return GameMain.GameSession.SubmarineInfo;
}
/// <summary>
@@ -1039,9 +1038,12 @@ namespace Barotrauma
if (item.HiddenInGame) { continue; }
if (!connectedSubs.Contains(item.Submarine)) { continue; }
if (item.Prefab.DontTransferBetweenSubs) { continue; }
if (item.GetRootInventoryOwner() is Character) { continue; }
if (item.GetComponent<Holdable>() == null && item.GetComponent<Wearable>() == null && item.GetComponent<Projectile>() == null) { continue; }
if (item.Components.Any(c => c is Holdable h && h.Attached)) { continue; }
var rootOwner = item.GetRootInventoryOwner();
if (rootOwner is Character) { continue; }
if (rootOwner is Item ownerItem && (ownerItem.NonInteractable || ownerItem.HiddenInGame)) { continue; }
if (item.GetComponent<Door>() != null) { continue; }
if (item.Components.None(c => c is Pickable)) { continue; }
if (item.Components.Any(c => c is Pickable p && p.IsAttached)) { continue; }
if (item.Components.Any(c => c is Wire w && w.Connections.Any(c => c != null))) { continue; }
itemsToTransfer.Add((item, item.Container));
item.Submarine = null;
@@ -1054,6 +1056,7 @@ namespace Barotrauma
item.Drop(null, createNetworkEvent: false, setTransform: false);
}
}
currentSub.Info.NoItems = true;
}
// Serialize the current sub
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(currentSub);
@@ -1122,6 +1125,7 @@ namespace Barotrauma
DebugConsole.Log(msg);
#endif
}
newSub.Info.NoItems = false;
// Serialize the new sub
PendingSubmarineSwitch = new SubmarineInfo(newSub);
}

View File

@@ -94,7 +94,7 @@ namespace Barotrauma
private CampaignMetadata Metadata => Campaign.CampaignMetadata;
private readonly CampaignMode Campaign;
public event Action? OnUpgradesChanged;
public readonly NamedEvent<UpgradeManager> OnUpgradesChanged = new NamedEvent<UpgradeManager>();
public UpgradeManager(CampaignMode campaign)
{
@@ -248,7 +248,7 @@ namespace Barotrauma
// tell the server that this item is yet to be paid for server side
PurchasedUpgrades.Add(new PurchasedUpgrade(prefab, category));
#endif
OnUpgradesChanged?.Invoke();
OnUpgradesChanged?.Invoke(this);
}
else
{
@@ -349,7 +349,7 @@ namespace Barotrauma
}
}
OnUpgradesChanged?.Invoke();
OnUpgradesChanged?.Invoke(this);
}
else
{
@@ -418,7 +418,7 @@ namespace Barotrauma
}
#if CLIENT
OnUpgradesChanged?.Invoke();
OnUpgradesChanged?.Invoke(this);
#endif
}
@@ -802,7 +802,7 @@ namespace Barotrauma
{
PendingUpgrades.Clear();
PendingUpgrades.AddRange(upgrades);
OnUpgradesChanged?.Invoke();
OnUpgradesChanged?.Invoke(this);
}
public static void DebugLog(string msg, Color? color = null)

View File

@@ -193,6 +193,9 @@ namespace Barotrauma.Items.Components
private Vector2 prevContainedItemPositions;
private float autoInjectCooldown = 1.0f;
const float AutoInjectInterval = 1.0f;
public bool ShouldBeContained(string[] identifiersOrTags, out bool isRestrictionsDefined)
{
@@ -412,7 +415,15 @@ namespace Barotrauma.Items.Components
if (AutoInject)
{
if (ownerInventory?.Owner is Character ownerCharacter &&
//normally autoinjection should delete the (medical) item, so it only gets applied once
//but in multiplayer clients aren't allowed to remove items themselves, so they may be able to trigger this dozens of times
//before the server notifies them of the item being removed, leading to a sharp lag spike.
//this can also happen with mods, if there's a way to autoinject something that doesn't get removed On Use.
//so let's ensure the item is only applied once per second at most.
autoInjectCooldown -= deltaTime;
if (autoInjectCooldown <= 0.0f &&
ownerInventory?.Owner is Character ownerCharacter &&
ownerCharacter.HealthPercentage / 100f <= AutoInjectThreshold &&
ownerCharacter.HasEquippedItem(item))
{
@@ -420,6 +431,7 @@ namespace Barotrauma.Items.Components
{
item.ApplyStatusEffects(ActionType.OnUse, 1.0f, ownerCharacter);
item.GetComponent<GeneticMaterial>()?.Equip(ownerCharacter);
autoInjectCooldown = AutoInjectInterval;
}
}
}

View File

@@ -338,9 +338,7 @@ namespace Barotrauma.Items.Components
if (user == null) { return; }
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign)
{
#if CLIENT
mpCampaign.TryPurchase(null, fabricatedItem.RequiredMoney);
#elif SERVER
#if SERVER
if (GetUsingClient() is { } client)
{
mpCampaign.TryPurchase(client, fabricatedItem.RequiredMoney);

View File

@@ -142,9 +142,8 @@ namespace Barotrauma.Items.Components
//less effective when in a bad condition
currFlow *= MathHelper.Lerp(0.5f, 1.0f, item.Condition / item.MaxCondition);
item.CurrentHull.WaterVolume += currFlow * deltaTime * Timing.FixedUpdateRate;
item.CurrentHull.WaterVolume += currFlow * deltaTime * Timing.FixedUpdateRate;
if (item.CurrentHull.WaterVolume > item.CurrentHull.Volume) { item.CurrentHull.Pressure += 30.0f * deltaTime; }
}
public void InfectBallast(Identifier identifier, bool allowMultiplePerShip = false)

View File

@@ -789,6 +789,11 @@ namespace Barotrauma.Items.Components
private bool ShouldIgnoreSubmarineCollision(ref Fixture target, Contact contact)
{
//not in the projectile category: the projectile has not been launched (e.g. just dropped from an inventory)
if (item.body.CollisionCategories != Physics.CollisionProjectile)
{
return false;
}
if (target.Body.UserData is Submarine sub)
{
Vector2 dir = item.body.LinearVelocity.LengthSquared() < 0.001f ?

View File

@@ -877,6 +877,7 @@ namespace Barotrauma
//and check if the collision should be ignored in the OnCollision callback, but
//that'd make the hit detection more expensive because every item would be included)
collisionCategory = Physics.CollisionCharacter;
collidesWith |= Physics.CollisionProjectile;
}
if (collisionCategoryStr != null)
{
@@ -1265,8 +1266,8 @@ namespace Barotrauma
Vector2 displayPos = ConvertUnits.ToDisplayUnits(simPosition);
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
rect.X = (int)MathF.Round(displayPos.X - rect.Width / 2.0f);
rect.Y = (int)MathF.Round(displayPos.Y + rect.Height / 2.0f);
if (findNewHull) { FindHull(); }
}

View File

@@ -403,13 +403,14 @@ namespace Barotrauma.MapCreatures.Behavior
new XAttribute("health", branch.Health.ToString("G", CultureInfo.InvariantCulture)),
new XAttribute("maxhealth", branch.MaxHealth.ToString("G", CultureInfo.InvariantCulture)),
new XAttribute("sides", (int)branch.Sides),
new XAttribute("blockedsides", (int)branch.BlockedSides));
new XAttribute("blockedsides", (int)branch.BlockedSides),
new XAttribute("tile", (int)branch.Type));
if (branch.ClaimedItem != null)
{
be.Add(new XAttribute("claimed", (int)(branch.ClaimedItem?.ID ?? -1)));
}
if (branch.ParentBranch != null)
if (branch.ParentBranch != null && !branch.ParentBranch.Removed)
{
be.Add(new XAttribute("parentbranch", (int)(branch.ParentBranch?.ID ?? -1)));
}
@@ -495,14 +496,15 @@ namespace Barotrauma.MapCreatures.Behavior
int blockedSides = getInt("blockedsides");
int claimedId = branchElement.GetAttributeInt("claimed", -1);
int parentBranchId = branchElement.GetAttributeInt("parentbranch", -1);
VineTileType type = (VineTileType)branchElement.GetAttributeInt("tile", 0);
BallastFloraBranch newBranch = new BallastFloraBranch(this, null, pos, VineTileType.CrossJunction, FoliageConfig.Deserialize(flowerConfig), FoliageConfig.Deserialize(leafconfig))
BallastFloraBranch newBranch = new BallastFloraBranch(this, null, pos, type, FoliageConfig.Deserialize(flowerConfig), FoliageConfig.Deserialize(leafconfig))
{
ID = id,
Health = health,
MaxHealth = maxhealth,
Sides = (TileSide) sides,
BlockedSides = (TileSide) blockedSides,
Sides = (TileSide)sides,
BlockedSides = (TileSide)blockedSides,
IsRoot = isRoot,
IsRootGrowth = isRootGrowth
};
@@ -683,7 +685,6 @@ namespace Barotrauma.MapCreatures.Behavior
if (branch.ClaimedItem != null)
{
RemoveClaim(branch.ClaimedItem);
branch.ClaimedItem = null;
}
branch.RemoveTimer -= deltaTime;
@@ -1196,6 +1197,14 @@ namespace Barotrauma.MapCreatures.Behavior
ClaimedTargets.Remove(item);
item.Infector = null;
foreach (var branch in Branches)
{
if (branch.ClaimedItem == item)
{
branch.ClaimedItem = null;
}
}
ClaimedJunctionBoxes.ForEachMod(jb =>
{
if (jb.Item == item)
@@ -1226,10 +1235,14 @@ namespace Barotrauma.MapCreatures.Behavior
branch.DisconnectedFromRoot = true;
}
foreach (Item target in ClaimedTargets)
foreach (Item target in ClaimedTargets.ToList())
{
RemoveClaim(target);
target.Infector = null;
}
Debug.Assert(ClaimedTargets.Count == 0);
Debug.Assert(ClaimedJunctionBoxes.Count == 0);
Debug.Assert(ClaimedBatteries.Count == 0);
StateMachine?.State?.Exit();
#if SERVER

View File

@@ -549,7 +549,7 @@ namespace Barotrauma
startPath = new Tunnel(
TunnelType.SidePath,
new List<Point>() { startExitPosition, startPosition },
minWidth / 2, parentTunnel: mainPath);
minWidth, parentTunnel: mainPath);
Tunnels.Add(startPath);
}
else
@@ -561,7 +561,7 @@ namespace Barotrauma
endPath = new Tunnel(
TunnelType.SidePath,
new List<Point>() { endPosition, endExitPosition },
minWidth / 2, parentTunnel: mainPath);
minWidth, parentTunnel: mainPath);
Tunnels.Add(endPath);
}
else
@@ -576,14 +576,14 @@ namespace Barotrauma
endHole = new Tunnel(
TunnelType.SidePath,
new List<Point>() { startPosition, startExitPosition, new Point(0, Size.Y) },
minWidth / 2, parentTunnel: mainPath);
minWidth, parentTunnel: mainPath);
}
else
{
endHole = new Tunnel(
TunnelType.SidePath,
new List<Point>() { endPosition, endExitPosition, Size },
minWidth / 2, parentTunnel: mainPath);
minWidth, parentTunnel: mainPath);
}
Tunnels.Add(endHole);
}
@@ -601,7 +601,7 @@ namespace Barotrauma
abyssTunnel = new Tunnel(
TunnelType.SidePath,
new List<Point>() { lowestPoint, new Point(lowestPoint.X, 0) },
minWidth / 2, parentTunnel: mainPath);
minWidth, parentTunnel: mainPath);
Tunnels.Add(abyssTunnel);
}
@@ -4266,6 +4266,7 @@ namespace Barotrauma
corpse.TeamID = CharacterTeamType.None;
corpse.EnableDespawn = false;
selectedPrefab.GiveItems(corpse, wreck);
corpse.Kill(CauseOfDeathType.Unknown, causeOfDeathAffliction: null, log: false);
corpse.CharacterHealth.ApplyAffliction(corpse.AnimController.MainLimb, AfflictionPrefab.OxygenLow.Instantiate(200));
bool applyBurns = Rand.Value() < 0.1f;
bool applyDamage = Rand.Value() < 0.3f;
@@ -4294,7 +4295,7 @@ namespace Barotrauma
return strength;
}
}
corpse.Kill(CauseOfDeathType.Unknown, causeOfDeathAffliction: null, log: false);
corpse.CharacterHealth.ForceUpdateVisuals();
corpse.GiveIdCardTags(sp);
bool isServerOrSingleplayer = GameMain.IsSingleplayer || GameMain.NetworkMember is { IsServer: true };

View File

@@ -182,8 +182,8 @@ namespace Barotrauma
float scale = element.GetAttributeFloat("scale", prefab.Scale);
var rect = element.GetAttributeVector4("rect", Vector4.Zero);
rect.Z *= scale / prefab.Scale;
rect.W *= scale / prefab.Scale;
if (!prefab.ResizeHorizontal) { rect.Z *= scale / prefab.Scale; }
if (!prefab.ResizeVertical) { rect.W *= scale / prefab.Scale; }
points.Add(new Vector2(rect.X, rect.Y));
points.Add(new Vector2(rect.X + rect.Z, rect.Y));
@@ -212,7 +212,9 @@ namespace Barotrauma
LevelData levelData = GameMain.GameSession?.Campaign?.NextLevel ?? GameMain.GameSession?.LevelData;
linkedSub = new LinkedSubmarine(submarine, id)
{
purchasedLostShuttles = GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles,
purchasedLostShuttles =
(GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles) ||
element.GetAttributeBool("purchasedlostshuttle", false),
saveElement = element
};
@@ -282,6 +284,8 @@ namespace Barotrauma
return;
}
saveElement.Attribute("purchasedlostshuttle")?.Remove();
IdRemap parentRemap = new IdRemap(Submarine.Info.SubmarineElement, Submarine.IdOffset);
sub = Submarine.Load(info, false, parentRemap);
sub.Info.SubmarineClass = Submarine.Info.SubmarineClass;
@@ -442,14 +446,19 @@ namespace Barotrauma
saveElement.Attribute("previewimage").Remove();
}
if (saveElement.Attribute("pos") != null) { saveElement.Attribute("pos").Remove(); }
saveElement.Add(new XAttribute("pos", XMLExtensions.Vector2ToString(Position - Submarine.HiddenSubPosition)));
if (GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles)
{
saveElement.SetAttributeValue("purchasedlostshuttle", true);
}
var linkedPort = linkedTo.FirstOrDefault(lt => (lt is Item) && ((Item)lt).GetComponent<DockingPort>() != null);
saveElement.SetAttributeValue("pos", XMLExtensions.Vector2ToString(Position - Submarine.HiddenSubPosition));
var linkedPort =
linkedTo.FirstOrDefault(lt => (lt is Item item) && item.GetComponent<DockingPort>() != null) ??
FindEntityByID(linkedToID.First()) as MapEntity;
if (linkedPort != null)
{
saveElement.Attribute("linkedto")?.Remove();
saveElement.Add(new XAttribute("linkedto", linkedPort.ID));
saveElement.SetAttributeValue("linkedto", linkedPort.ID);
}
}
else
@@ -458,10 +467,8 @@ namespace Barotrauma
sub.SaveToXElement(saveElement);
}
saveElement.Attribute("originallinkedto")?.Remove();
saveElement.Add(new XAttribute("originallinkedto", originalLinkedPort != null ? originalLinkedPort.Item.ID : originalLinkedToID));
saveElement.Attribute("originalmyport")?.Remove();
saveElement.Add(new XAttribute("originalmyport", originalMyPortID));
saveElement.SetAttributeValue("originallinkedto", originalLinkedPort != null ? originalLinkedPort.Item.ID : originalLinkedToID);
saveElement.SetAttributeValue("originalmyport", originalMyPortID);
if (sub != null)
{

View File

@@ -20,11 +20,24 @@ namespace Barotrauma
public int Height { get; private set; }
public Action<Location, LocationConnection> OnLocationSelected;
public Action<LocationConnection, IEnumerable<Mission>> OnMissionsSelected;
public readonly struct LocationChangeInfo
{
public readonly Location PrevLocation;
public readonly Location NewLocation;
public LocationChangeInfo(Location prevLocation, Location newLocation)
{
PrevLocation = prevLocation;
NewLocation = newLocation;
}
}
/// <summary>
/// From -> To
/// </summary>
public Action<Location, Location> OnLocationChanged;
public Action<LocationConnection, IEnumerable<Mission>> OnMissionsSelected;
public readonly NamedEvent<LocationChangeInfo> OnLocationChanged = new NamedEvent<LocationChangeInfo>();
public Location EndLocation { get; private set; }
@@ -766,7 +779,7 @@ namespace Barotrauma
SelectedLocation = null;
CurrentLocation.CreateStores();
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
OnLocationChanged?.Invoke(new LocationChangeInfo(prevLocation, CurrentLocation));
if (GameMain.GameSession is { Campaign: { CampaignMetadata: { } metadata } })
{
@@ -803,7 +816,7 @@ namespace Barotrauma
{
connection.Passed = true;
}
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
OnLocationChanged?.Invoke(new LocationChangeInfo(prevLocation, CurrentLocation));
}
}

View File

@@ -540,6 +540,7 @@ namespace Barotrauma
mapEntityList.Remove(this);
#if CLIENT
Submarine.ForceRemoveFromVisibleEntities(this);
if (SelectedList.Contains(this))
{
SelectedList = SelectedList.Where(e => e != this).ToHashSet();

View File

@@ -52,7 +52,9 @@ namespace Barotrauma
get { return MainSubs[0]; }
set { MainSubs[0] = value; }
}
private static List<Submarine> loaded = new List<Submarine>();
private static readonly List<Submarine> loaded = new List<Submarine>();
private readonly Identifier upgradeEventIdentifier;
private static List<MapEntity> visibleEntities;
public static IEnumerable<MapEntity> VisibleEntities
@@ -1301,6 +1303,7 @@ namespace Barotrauma
public Submarine(SubmarineInfo info, bool showWarningMessages = true, Func<Submarine, List<MapEntity>> loadEntities = null, IdRemap linkedRemap = null) : base(null, Entity.NullEntityID)
{
upgradeEventIdentifier = new Identifier($"Submarine{ID}");
Loading = true;
GameMain.World.Enabled = false;
try
@@ -1462,10 +1465,7 @@ namespace Barotrauma
}
}
if (GameMain.GameSession?.Campaign?.UpgradeManager != null)
{
GameMain.GameSession.Campaign.UpgradeManager.OnUpgradesChanged += ResetCrushDepth;
}
GameMain.GameSession?.Campaign?.UpgradeManager?.OnUpgradesChanged.Register(upgradeEventIdentifier, _ => ResetCrushDepth());
#if CLIENT
GameMain.LightManager.OnMapLoaded();
@@ -1527,6 +1527,13 @@ namespace Barotrauma
}
}
public bool CheckFuel()
{
float fuel = GetItems(true).Where(i => i.HasTag("reactorfuel")).Sum(i => i.Condition);
Info.LowFuel = fuel < 200;
return !Info.LowFuel;
}
public void SaveToXElement(XElement element)
{
element.Add(new XAttribute("name", Info.Name));
@@ -1534,7 +1541,10 @@ namespace Barotrauma
element.Add(new XAttribute("checkval", Rand.Int(int.MaxValue)));
element.Add(new XAttribute("price", Info.Price));
element.Add(new XAttribute("initialsuppliesspawned", Info.InitialSuppliesSpawned));
element.Add(new XAttribute("noitems", Info.NoItems));
element.Add(new XAttribute("lowfuel", !CheckFuel()));
element.Add(new XAttribute("type", Info.Type.ToString()));
element.Add(new XAttribute("ismanuallyoutfitted", Info.IsManuallyOutfitted));
if (Info.IsPlayer && !Info.HasTag(SubmarineTag.Shuttle))
{
element.Add(new XAttribute("class", Info.SubmarineClass.ToString()));
@@ -1623,7 +1633,6 @@ namespace Barotrauma
e.Save(element);
}
Info.CheckSubsLeftBehind(element);
}
@@ -1727,10 +1736,7 @@ namespace Barotrauma
outdoorNodes?.Clear();
outdoorNodes = null;
if (GameMain.GameSession?.Campaign?.UpgradeManager != null)
{
GameMain.GameSession.Campaign.UpgradeManager.OnUpgradesChanged -= ResetCrushDepth;
}
GameMain.GameSession?.Campaign?.UpgradeManager?.OnUpgradesChanged?.TryDeregister(upgradeEventIdentifier);
if (entityGrid != null)
{

View File

@@ -598,7 +598,12 @@ namespace Barotrauma
if (newHull != null)
{
CoroutineManager.Invoke(() =>
character.AnimController.FindHull(newHull.WorldPosition, setSubmarine: true));
{
if (character != null && !character.Removed)
{
character.AnimController.FindHull(newHull.WorldPosition, setSubmarine: true);
}
});
}
return false;

View File

@@ -86,6 +86,18 @@ namespace Barotrauma
set;
}
public bool NoItems
{
get;
set;
}
public bool LowFuel
{
get;
set;
}
public Version GameVersion
{
get;
@@ -94,6 +106,8 @@ namespace Barotrauma
public SubmarineType Type { get; set; }
public bool IsManuallyOutfitted { get; set; }
public SubmarineClass SubmarineClass;
public OutpostModuleInfo OutpostModuleInfo { get; set; }
@@ -272,6 +286,8 @@ namespace Barotrauma
Description = original.Description;
Price = original.Price;
InitialSuppliesSpawned = original.InitialSuppliesSpawned;
NoItems = original.NoItems;
LowFuel = original.LowFuel;
GameVersion = original.GameVersion;
Type = original.Type;
SubmarineClass = original.SubmarineClass;
@@ -286,6 +302,7 @@ namespace Barotrauma
RecommendedCrewExperience = original.RecommendedCrewExperience;
RecommendedCrewSizeMin = original.RecommendedCrewSizeMin;
RecommendedCrewSizeMax = original.RecommendedCrewSizeMax;
IsManuallyOutfitted = original.IsManuallyOutfitted;
Tags = original.Tags;
if (original.OutpostModuleInfo != null)
{
@@ -335,6 +352,9 @@ namespace Barotrauma
Price = SubmarineElement.GetAttributeInt("price", 1000);
InitialSuppliesSpawned = SubmarineElement.GetAttributeBool("initialsuppliesspawned", false);
NoItems = SubmarineElement.GetAttributeBool("noitems", false);
LowFuel = SubmarineElement.GetAttributeBool("lowfuel", false);
IsManuallyOutfitted = SubmarineElement.GetAttributeBool("ismanuallyoutfitted", false);
GameVersion = new Version(SubmarineElement.GetAttributeString("gameversion", "0.0.0.0"));
if (Enum.TryParse(SubmarineElement.GetAttributeString("tags", ""), out SubmarineTag tags))

View File

@@ -284,7 +284,7 @@ namespace Barotrauma.Networking
if (hull.Submarine != RespawnShuttle) { continue; }
hull.OxygenPercentage = 100.0f;
hull.WaterVolume = 0.0f;
hull.BallastFlora?.Kill();
hull.BallastFlora?.Remove();
}
Dictionary<Character, Vector2> characterPositions = new Dictionary<Character, Vector2>();

View File

@@ -1,17 +1,12 @@
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
using Barotrauma.IO;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Globalization;
using Barotrauma.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma.Networking
{

View File

@@ -405,6 +405,8 @@ namespace Barotrauma
FarseerBody.Restitution = limbParams.Restitution;
FarseerBody.AngularDamping = limbParams.AngularDamping;
FarseerBody.UserData = this;
_collisionCategories = collisionCategory;
_collidesWith = collidesWith;
SetTransformIgnoreContacts(position, 0.0f);
LastSentPosition = position;
list.Add(this);
@@ -418,6 +420,8 @@ namespace Barotrauma
density = Math.Max(forceDensity ?? element.GetAttributeFloat("density", 10.0f), MinDensity);
Enum.TryParse(element.GetAttributeString("bodytype", "Dynamic"), out BodyType bodyType);
CreateBody(width, height, radius, density, bodyType, collisionCategory, collidesWith, findNewContacts);
_collisionCategories = collisionCategory;
_collidesWith = collidesWith;
FarseerBody.Friction = element.GetAttributeFloat("friction", 0.5f);
FarseerBody.Restitution = element.GetAttributeFloat("restitution", 0.05f);
FarseerBody.UserData = this;
@@ -456,6 +460,8 @@ namespace Barotrauma
this.width = width;
this.height = height;
this.radius = radius;
_collisionCategories = collisionCategory;
_collidesWith = collidesWith;
}
/// <summary>

View File

@@ -54,7 +54,6 @@ namespace Barotrauma
EnableMouseLook = true,
ChatOpen = true,
CrewMenuOpen = true,
CampaignDisclaimerShown = false,
EditorDisclaimerShown = false,
ShowOffensiveServerPrompt = true,
TutorialSkipWarning = true,
@@ -127,7 +126,6 @@ namespace Barotrauma
public bool EnableMouseLook;
public bool ChatOpen;
public bool CrewMenuOpen;
public bool CampaignDisclaimerShown;
public bool EditorDisclaimerShown;
public bool ShowOffensiveServerPrompt;
public bool TutorialSkipWarning;

View File

@@ -6,11 +6,11 @@ namespace Barotrauma
private readonly LocalizedString primary;
private readonly LocalizedString fallback;
private bool primaryIsLoaded = false;
public bool PrimaryIsLoaded { get; private set; }
public FallbackLString(LocalizedString primary, LocalizedString fallback)
{
if (primary is FallbackLString {primary: { } innerPrimary, fallback: { } innerFallback})
if (primary is FallbackLString { primary: { } innerPrimary, fallback: { } innerFallback })
{
this.primary = innerPrimary;
this.fallback = innerFallback.Fallback(fallback);
@@ -27,18 +27,27 @@ namespace Barotrauma
return base.MustRetrieveValue()
|| MustRetrieveValue(primary)
|| MustRetrieveValue(fallback)
|| primaryIsLoaded != primary.Loaded;
|| PrimaryIsLoaded != primary.Loaded;
}
public override bool Loaded => primary.Loaded || fallback.Loaded;
public override void RetrieveValue()
{
cachedValue = primary.Value;
primaryIsLoaded = primary.Loaded;
PrimaryIsLoaded = primary.Loaded;
if (!primary.Loaded)
{
cachedValue = fallback.Value;
}
}
public LocalizedString GetLastFallback()
{
if (fallback is FallbackLString innerFallback)
{
return innerFallback.GetLastFallback();
}
return fallback;
}
}
}

View File

@@ -1,4 +1,5 @@
#nullable enable
using System;
using System.Collections.Immutable;
using System.Linq;
@@ -18,7 +19,14 @@ namespace Barotrauma
public override void RetrieveValue()
{
//TODO: possibly broken!
cachedValue = string.Format(str.Value, subStrs.Select(s => s.Value as object).ToArray());
try
{
cachedValue = string.Format(str.Value, subStrs.Select(s => s.Value as object).ToArray());
}
catch (FormatException)
{
cachedValue = str.Value;
}
UpdateLanguage();
}
}

View File

@@ -1,3 +1,64 @@
---------------------------------------------------------------------------------------------------------
v0.18.13.0
---------------------------------------------------------------------------------------------------------
Changes:
- Show a warning when trying to switch to a submarine that's low on fuel.
- Also show the low fuel warning when leaving an outpost without enough fuel.
- Items are always transferred when switching to a submarine that has no manually placed items, which should prevent softlocking the campaign if you switch to a sub that has no fuel. Whether a submarine is considered to have manually placed items can be set when saving it in the submarine editor (the checkbox "manually outfitted" in the saving dialog).
- Handheld sonars can't detect minerals from inside the sub.
- Changed the plus and minus button in the campaign settings into arrows. The button on the right increases difficulty, which in the case of the starting balance and supplies means reducing them, making the plus and minus buttons misleading.
- Reduced costs of handheld weapon ammunition significantly.
- Slightly reduced effectiveness of harpoons and revolver round to compensate for the cheaper ammo.
- Changed recipes for Handcannon, Assault Rifle and Auto-Shotgun. Weapon crafting is more expensive, to compensate for cheaper ammo.
- Adjusted numerous other recipes and price costs of materials. Previously little used materials (like tin) are now used more.
Fixes:
- Fixed shuttles getting misplaced when switching and transferring items to a new sub with shuttles.
- Fixed inability to damage items (such as monster eggs) with melee weapons or handheld weapons.
- Fixed "failed to parse the string 'COLOR.GUI.GREEN' to Color" errors when using the submarine upgrade interface in Spanish.
- Fixed items with a projectile component (e.g. bullets, harpoons, syringes) going through external walls when dropped.
- Fixed incorrect value in the "too many lights" error message in the sub editor.
- Fixed lightcomponent not getting refreshed when flipping a lightcomponent horizontally.
- Fixed extra cargo defined in the server settings spawning every round in multiplayer campaign.
- Fixes wreck corpses' damage visuals (bloodstains, burns) not showing client-side.
- Fixed wearables that are worn (or held) in multiple limbs applying skill bonuses multiple times (e.g. when holding a bandolier with both hands).
- Fixed console error when deselecting all target types from a motion sensor in the sub editor.
- Fixed crashing when multi-editing motion sensor targets in the sub editor.
- Fixed one of the path unlock event texts still using the old price (talking about 12,000 mk even though the price is 4,000 mk).
- Fixed money getting incorrectly deducted on the client side when buying items from the vending machine.
- Fixed item transfer taking items from non-interactable containers.
- Made depleted fuel sprite darker to match the rest of the "depleted" items.
- Fixed PUCS's autoinjection feature sometimes causing performance drops in multiplayer.
- Fixed "tried to overwrite a submarine that's not in a local package" error when you delete a sub that's in a local package and try to resave it.
- Fixed misaligned broken duffelbag sprite.
- Fixed full-white x-ray monitors.
- Fixed FPS drop when adjusting character appearance in the campaign setup menu or server lobby.
- Fixed tunnels at the beginning or end of the level sometimes being too narrow to pass through (especially with a small sub) when there's no outpost at that side of the level.
- Fixed missing background sprite in duct block.
- Fixed water particles not showing up when water is flowing down a duct block.
- Fixed changing the scale of resizeable structures (such as background doors) messing up the outline of linked subs in the sub editor.
- Fixed friendly fire and karma always showing up as disabled on dedicated servers in the server list.
Modding:
- Fixed removing a door mid-round crashing the game. Does not affect the vanilla game, because doors are never removed mid-round.
- Fixed having a vending machine in your inventory crashing the game due to the 0-capacity input inventory of the machine.
---------------------------------------------------------------------------------------------------------
v0.18.12.0
---------------------------------------------------------------------------------------------------------
- Fixed medical doctor tutorial throwing an error and freezing in most languages other than English.
- Fixed occasional disconnects with the error "the given key was not present in the dictionary" when giving orders or reporting things in multiplayer.
- Fixed occasional crashes caused by AIObjectivePumpWater.
- Fixed certain looping item sounds (oxygen generators, vents, reactor) being too quiet to hear.
- Fixed one of texts not appearing in the "captive souls" event.
- Fixed inability to fabricate rubber shells.
Modding:
- Fixed crashing when a MonsterEvent fails to find the character prefab.
---------------------------------------------------------------------------------------------------------
v0.18.11.0
---------------------------------------------------------------------------------------------------------