Unstable 0.1400.3.0 (Bad sleep schedule edition)
This commit is contained in:
@@ -698,6 +698,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsMouseOnHealthBar()
|
||||
{
|
||||
if (Character.Controlled?.CharacterHealth == null) { return false; }
|
||||
return Character.Controlled.CharacterHealth.healthBar.State == GUIComponent.ComponentState.Hover;
|
||||
}
|
||||
|
||||
public void UpdateHUD(float deltaTime)
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
@@ -966,11 +972,9 @@ namespace Barotrauma
|
||||
highlightedLimbIndex = -1;
|
||||
}
|
||||
|
||||
Rectangle hoverArea = Rectangle.Union(HUDLayoutSettings.AfflictionAreaLeft, HUDLayoutSettings.HealthBarArea);
|
||||
|
||||
healthBarHolder.CanBeFocused = healthBar.CanBeFocused = healthBarShadow.CanBeFocused = !Character.ShouldLockHud();
|
||||
if (Character.AllowInput && UseHealthWindow && healthBar.Enabled && healthBar.CanBeFocused &&
|
||||
hoverArea.Contains(PlayerInput.MousePosition) && Inventory.SelectedSlot == null)
|
||||
(GUI.IsMouseOn(healthBar) || highlightedAfflictionIcon != null) && Inventory.SelectedSlot == null)
|
||||
{
|
||||
healthBar.State = GUIComponent.ComponentState.Hover;
|
||||
if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
@@ -1087,8 +1091,11 @@ namespace Barotrauma
|
||||
DrawStatusHUD(spriteBatch);
|
||||
}
|
||||
|
||||
|
||||
private Pair<Affliction, string> highlightedAfflictionIcon = null;
|
||||
public void DrawStatusHUD(SpriteBatch spriteBatch)
|
||||
{
|
||||
highlightedAfflictionIcon = null;
|
||||
//Rectangle interactArea = healthBar.Rect;
|
||||
if (Character.Controlled?.SelectedCharacter == null && openHealthWindow == null)
|
||||
{
|
||||
@@ -1103,7 +1110,6 @@ namespace Barotrauma
|
||||
statusIcons.Add(new Pair<Affliction, string>(affliction, affliction.Prefab.Name));
|
||||
}
|
||||
|
||||
Pair<Affliction, string> highlightedIcon = null;
|
||||
Vector2 highlightedIconPos = Vector2.Zero;
|
||||
Rectangle afflictionArea = HUDLayoutSettings.AfflictionAreaLeft;
|
||||
|
||||
@@ -1124,9 +1130,9 @@ namespace Barotrauma
|
||||
AfflictionPrefab afflictionPrefab = affliction.Prefab;
|
||||
|
||||
Rectangle afflictionIconRect = new Rectangle(pos, new Point(iconSize));
|
||||
if (afflictionIconRect.Contains(PlayerInput.MousePosition) && !Character.ShouldLockHud())
|
||||
if (afflictionIconRect.Contains(PlayerInput.MousePosition) && !Character.ShouldLockHud() && GUI.MouseOn == null)
|
||||
{
|
||||
highlightedIcon = statusIcon;
|
||||
highlightedAfflictionIcon = statusIcon;
|
||||
highlightedIconPos = afflictionIconRect.Location.ToVector2();
|
||||
}
|
||||
|
||||
@@ -1146,7 +1152,7 @@ namespace Barotrauma
|
||||
highlightedIcon == statusIcon ? slot.HoverColor : slot.Color);*/
|
||||
|
||||
|
||||
float alphaMultiplier = highlightedIcon == statusIcon ? 1f : 0.8f;
|
||||
float alphaMultiplier = highlightedAfflictionIcon == statusIcon ? 1f : 0.8f;
|
||||
|
||||
afflictionPrefab.Icon?.Draw(spriteBatch,
|
||||
pos.ToVector2(),
|
||||
@@ -1161,9 +1167,9 @@ namespace Barotrauma
|
||||
pos.Y += iconSize + (int)(5 * GUI.Scale);
|
||||
}
|
||||
|
||||
if (highlightedIcon != null)
|
||||
if (highlightedAfflictionIcon != null)
|
||||
{
|
||||
string nameTooltip = highlightedIcon.Second;
|
||||
string nameTooltip = highlightedAfflictionIcon.Second;
|
||||
Vector2 offset = GUI.Font.MeasureString(nameTooltip);
|
||||
|
||||
GUI.DrawString(spriteBatch,
|
||||
|
||||
@@ -997,8 +997,7 @@ namespace Barotrauma
|
||||
return editor.GetMouseCursorState();
|
||||
// Portrait area during gameplay
|
||||
case GameScreen _ when !(Character.Controlled?.ShouldLockHud() ?? true):
|
||||
if (HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) ||
|
||||
Rectangle.Union(HUDLayoutSettings.AfflictionAreaLeft, HUDLayoutSettings.HealthBarArea).Contains(PlayerInput.MousePosition))
|
||||
if (HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) || CharacterHealth.IsMouseOnHealthBar())
|
||||
{
|
||||
return CursorState.Hand;
|
||||
}
|
||||
|
||||
@@ -17,47 +17,63 @@ namespace Barotrauma
|
||||
private readonly Dictionary<StoreTab, GUIListBox> tabLists = new Dictionary<StoreTab, GUIListBox>();
|
||||
private readonly Dictionary<StoreTab, SortingMethod> tabSortingMethods = new Dictionary<StoreTab, SortingMethod>();
|
||||
private readonly List<PurchasedItem> itemsToSell = new List<PurchasedItem>();
|
||||
private readonly List<PurchasedItem> itemsToSellFromSub = new List<PurchasedItem>();
|
||||
|
||||
private StoreTab activeTab = StoreTab.Buy;
|
||||
private MapEntityCategory? selectedItemCategory;
|
||||
private bool suppressBuySell;
|
||||
private int buyTotal, sellTotal;
|
||||
private int buyTotal, sellTotal, sellFromSubTotal;
|
||||
|
||||
private GUITextBlock merchantBalanceBlock;
|
||||
private GUITextBlock currentSellValueBlock, newSellValueBlock;
|
||||
private GUIImage sellValueChangeArrow;
|
||||
private GUIDropDown sortingDropDown;
|
||||
private GUITextBox searchBox;
|
||||
private GUIListBox storeBuyList, storeSellList;
|
||||
private GUIListBox storeBuyList, storeSellList, storeSellFromSubList;
|
||||
/// <summary>
|
||||
/// Can be null when there are no deals at the current location
|
||||
/// </summary>
|
||||
private GUILayoutGroup storeDailySpecialsGroup, storeRequestedGoodGroup;
|
||||
private GUILayoutGroup storeDailySpecialsGroup, storeRequestedGoodGroup, storeRequestedSubGoodGroup;
|
||||
private Color storeSpecialColor;
|
||||
|
||||
private GUIListBox shoppingCrateBuyList, shoppingCrateSellList;
|
||||
private GUIListBox shoppingCrateBuyList, shoppingCrateSellList, shoppingCrateSellFromSubList;
|
||||
private GUITextBlock shoppingCrateTotal;
|
||||
private GUIButton clearAllButton, confirmButton;
|
||||
|
||||
private bool needsRefresh, needsBuyingRefresh, needsSellingRefresh, needsItemsToSellRefresh;
|
||||
private bool needsRefresh, needsBuyingRefresh, needsSellingRefresh, needsItemsToSellRefresh, needsSellingFromSubRefresh, needsItemsToSellFromSubRefresh;
|
||||
|
||||
private Point resolutionWhenCreated;
|
||||
private bool hadPermissions;
|
||||
|
||||
private Dictionary<ItemPrefab, int> OwnedItems { get; } = new Dictionary<ItemPrefab, int>();
|
||||
private Dictionary<ItemPrefab, int> OwnedItems { get; } = new Dictionary<ItemPrefab, int>();
|
||||
|
||||
private CargoManager CargoManager => campaignUI.Campaign.CargoManager;
|
||||
private Location CurrentLocation => campaignUI.Campaign.Map?.CurrentLocation;
|
||||
private int PlayerMoney => campaignUI.Campaign.Money;
|
||||
private bool HasPermissions => campaignUI.Campaign.AllowedToManageCampaign();
|
||||
private bool IsBuying => activeTab != StoreTab.Sell;
|
||||
private bool IsSelling => activeTab == StoreTab.Sell;
|
||||
private GUIListBox ActiveShoppingCrateList => IsBuying ? shoppingCrateBuyList : shoppingCrateSellList;
|
||||
private bool IsBuying => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => true,
|
||||
StoreTab.Sell => false,
|
||||
StoreTab.SellFromSub => false,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
private bool IsSelling => !IsBuying;
|
||||
private GUIListBox ActiveShoppingCrateList => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => shoppingCrateBuyList,
|
||||
StoreTab.Sell => shoppingCrateSellList,
|
||||
StoreTab.SellFromSub => shoppingCrateSellFromSubList,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
private enum StoreTab
|
||||
private bool IsTabUnavailable(StoreTab tab) => !tabLists.ContainsKey(tab);
|
||||
|
||||
public enum StoreTab
|
||||
{
|
||||
Buy,
|
||||
Sell
|
||||
Sell,
|
||||
SellFromSub
|
||||
}
|
||||
|
||||
private enum SortingMethod
|
||||
@@ -73,11 +89,8 @@ namespace Barotrauma
|
||||
{
|
||||
this.campaignUI = campaignUI;
|
||||
this.parentComponent = parentComponent;
|
||||
|
||||
hadPermissions = HasPermissions;
|
||||
|
||||
CreateUI();
|
||||
|
||||
campaignUI.Campaign.Map.OnLocationChanged += UpdateLocation;
|
||||
if (CurrentLocation?.Reputation != null)
|
||||
{
|
||||
@@ -89,8 +102,10 @@ namespace Barotrauma
|
||||
campaignUI.Campaign.CargoManager.OnSoldItemsChanged += () =>
|
||||
{
|
||||
needsItemsToSellRefresh = true;
|
||||
needsItemsToSellFromSubRefresh = true;
|
||||
needsRefresh = true;
|
||||
};
|
||||
campaignUI.Campaign.CargoManager.OnItemsInSellFromSubCrateChanged += () => { needsSellingFromSubRefresh = true; };
|
||||
}
|
||||
|
||||
public void Refresh(bool updateOwned = true)
|
||||
@@ -99,6 +114,7 @@ namespace Barotrauma
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshBuying(updateOwned: false);
|
||||
RefreshSelling(updateOwned: false);
|
||||
RefreshSellingFromSub(updateOwned: false);
|
||||
needsRefresh = false;
|
||||
}
|
||||
|
||||
@@ -124,6 +140,20 @@ namespace Barotrauma
|
||||
needsSellingRefresh = false;
|
||||
}
|
||||
|
||||
private void RefreshSellingFromSub(bool updateOwned = true, bool updateItemsToSellFromSub = true)
|
||||
{
|
||||
if (IsTabUnavailable(StoreTab.SellFromSub)) { return; }
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
if (updateItemsToSellFromSub) RefreshItemsToSellFromSub();
|
||||
RefreshShoppingCrateSellFromSubList();
|
||||
RefreshStoreSellFromSubList();
|
||||
// TODO: Separate permissions from regular campaign permissions
|
||||
var hasPermissions = HasPermissions;
|
||||
storeSellFromSubList.Enabled = hasPermissions;
|
||||
shoppingCrateSellFromSubList.Enabled = hasPermissions;
|
||||
needsSellingFromSubRefresh = false;
|
||||
}
|
||||
|
||||
private void CreateUI()
|
||||
{
|
||||
if (parentComponent.FindChild(c => c.UserData as string == "glow") is GUIComponent glowChild)
|
||||
@@ -236,9 +266,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (CurrentLocation != null)
|
||||
{
|
||||
int balanceAfterTransaction = IsBuying ?
|
||||
CurrentLocation.StoreCurrentBalance + buyTotal :
|
||||
CurrentLocation.StoreCurrentBalance - sellTotal;
|
||||
int balanceAfterTransaction = activeTab switch
|
||||
{
|
||||
StoreTab.Buy => CurrentLocation.StoreCurrentBalance + buyTotal,
|
||||
StoreTab.Sell => CurrentLocation.StoreCurrentBalance - sellTotal,
|
||||
StoreTab.SellFromSub => CurrentLocation.StoreCurrentBalance - sellFromSubTotal,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
|
||||
{
|
||||
var newStatus = Location.GetStoreBalanceStatus(balanceAfterTransaction);
|
||||
@@ -300,8 +334,14 @@ namespace Barotrauma
|
||||
tabSortingMethods.Clear();
|
||||
foreach (StoreTab tab in tabs)
|
||||
{
|
||||
if (tab == StoreTab.SellFromSub && GameMain.IsMultiplayer) { continue; }
|
||||
string text = tab switch
|
||||
{
|
||||
StoreTab.SellFromSub => TextManager.Get("submarine"),
|
||||
_ => TextManager.Get("campaignstoretab." + tab)
|
||||
};
|
||||
var tabButton = new GUIButton(new RectTransform(new Vector2(1.0f / (tabs.Length + 1), 1.0f), modeButtonContainer.RectTransform),
|
||||
text: TextManager.Get("campaignstoretab." + tab), style: "GUITabButton")
|
||||
text: text, style: "GUITabButton")
|
||||
{
|
||||
UserData = tab,
|
||||
OnClicked = (button, userData) =>
|
||||
@@ -416,6 +456,17 @@ namespace Barotrauma
|
||||
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
|
||||
tabLists.Add(StoreTab.Sell, storeSellList);
|
||||
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
storeSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
Visible = false
|
||||
};
|
||||
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellFromSubList);
|
||||
tabLists.Add(StoreTab.SellFromSub, storeSellFromSubList);
|
||||
}
|
||||
|
||||
// Shopping Crate ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
var shoppingCrateContent = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1.0f), campaignUI.GetTabContainer(CampaignMode.InteractionType.Store).RectTransform, anchor: Anchor.TopRight)
|
||||
@@ -475,6 +526,10 @@ namespace Barotrauma
|
||||
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.85f), shoppingCrateInventoryContainer.RectTransform), style: null);
|
||||
shoppingCrateBuyList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
shoppingCrateSellList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
}
|
||||
|
||||
var totalContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
@@ -504,7 +559,13 @@ namespace Barotrauma
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
if (!HasPermissions) { return false; }
|
||||
var itemsToRemove = new List<PurchasedItem>(IsBuying ? CargoManager.ItemsInBuyCrate : CargoManager.ItemsInSellCrate);
|
||||
var itemsToRemove = activeTab switch
|
||||
{
|
||||
StoreTab.Buy => new List<PurchasedItem>(CargoManager.ItemsInBuyCrate),
|
||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
||||
StoreTab.SellFromSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
itemsToRemove.ForEach(i => ClearFromShoppingCrate(i));
|
||||
return true;
|
||||
}
|
||||
@@ -560,6 +621,7 @@ namespace Barotrauma
|
||||
|
||||
private void ChangeStoreTab(StoreTab tab)
|
||||
{
|
||||
if (IsTabUnavailable(tab)) { return; }
|
||||
activeTab = tab;
|
||||
foreach (GUIButton tabButton in storeTabButtons)
|
||||
{
|
||||
@@ -571,24 +633,56 @@ namespace Barotrauma
|
||||
SetConfirmButtonBehavior();
|
||||
SetConfirmButtonStatus();
|
||||
FilterStoreItems();
|
||||
if (tab == StoreTab.Buy)
|
||||
switch (tab)
|
||||
{
|
||||
storeSellList.Visible = false;
|
||||
storeBuyList.Visible = true;
|
||||
shoppingCrateSellList.Visible = false;
|
||||
shoppingCrateBuyList.Visible = true;
|
||||
}
|
||||
else if (tab == StoreTab.Sell)
|
||||
{
|
||||
storeBuyList.Visible = false;
|
||||
storeSellList.Visible = true;
|
||||
shoppingCrateBuyList.Visible = false;
|
||||
shoppingCrateSellList.Visible = true;
|
||||
case StoreTab.Buy:
|
||||
storeSellList.Visible = false;
|
||||
if (storeSellFromSubList != null)
|
||||
{
|
||||
storeSellFromSubList.Visible = false;
|
||||
}
|
||||
storeBuyList.Visible = true;
|
||||
shoppingCrateSellList.Visible = false;
|
||||
if (shoppingCrateSellFromSubList != null)
|
||||
{
|
||||
shoppingCrateSellFromSubList.Visible = false;
|
||||
}
|
||||
shoppingCrateBuyList.Visible = true;
|
||||
break;
|
||||
case StoreTab.Sell:
|
||||
storeBuyList.Visible = false;
|
||||
if (storeSellFromSubList != null)
|
||||
{
|
||||
storeSellFromSubList.Visible = false;
|
||||
}
|
||||
storeSellList.Visible = true;
|
||||
shoppingCrateBuyList.Visible = false;
|
||||
if (shoppingCrateSellFromSubList != null)
|
||||
{
|
||||
shoppingCrateSellFromSubList.Visible = false;
|
||||
}
|
||||
shoppingCrateSellList.Visible = true;
|
||||
break;
|
||||
case StoreTab.SellFromSub:
|
||||
storeBuyList.Visible = false;
|
||||
storeSellList.Visible = false;
|
||||
if (storeSellFromSubList != null)
|
||||
{
|
||||
storeSellFromSubList.Visible = true;
|
||||
}
|
||||
shoppingCrateBuyList.Visible = false;
|
||||
shoppingCrateSellList.Visible = false;
|
||||
if (shoppingCrateSellFromSubList != null)
|
||||
{
|
||||
shoppingCrateSellFromSubList.Visible = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterStoreItems(MapEntityCategory? category, string filter)
|
||||
{
|
||||
if (IsTabUnavailable(activeTab)) { return; }
|
||||
selectedItemCategory = category;
|
||||
var list = tabLists[activeTab];
|
||||
filter = filter?.ToLower();
|
||||
@@ -668,7 +762,7 @@ namespace Barotrauma
|
||||
if (itemFrame == null)
|
||||
{
|
||||
var parentComponent = isDailySpecial ? storeDailySpecialsGroup : storeBuyList as GUIComponent;
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, quantity), priceInfo, parentComponent, forceDisable: !hasPermissions);
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, quantity), parentComponent, StoreTab.Buy, forceDisable: !hasPermissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -688,7 +782,7 @@ namespace Barotrauma
|
||||
removedItemFrames.AddRange(storeDailySpecialsGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
|
||||
}
|
||||
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
|
||||
if (IsBuying) { FilterStoreItems(); }
|
||||
if (activeTab == StoreTab.Buy) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.Buy);
|
||||
|
||||
storeBuyList.BarScroll = prevBuyListScroll;
|
||||
@@ -743,7 +837,7 @@ namespace Barotrauma
|
||||
if (itemFrame == null)
|
||||
{
|
||||
var parentComponent = isRequestedGood ? storeRequestedGoodGroup : storeSellList as GUIComponent;
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), priceInfo, parentComponent, forceDisable: !hasPermissions);
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), parentComponent, StoreTab.Sell, forceDisable: !hasPermissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -766,13 +860,91 @@ namespace Barotrauma
|
||||
removedItemFrames.AddRange(storeRequestedGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
|
||||
}
|
||||
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
|
||||
if (IsSelling) { FilterStoreItems(); }
|
||||
if (activeTab == StoreTab.Sell) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.Sell);
|
||||
|
||||
storeSellList.BarScroll = prevSellListScroll;
|
||||
shoppingCrateSellList.BarScroll = prevShoppingCrateScroll;
|
||||
}
|
||||
|
||||
private void RefreshStoreSellFromSubList()
|
||||
{
|
||||
float prevSellListScroll = storeSellFromSubList.BarScroll;
|
||||
float prevShoppingCrateScroll = shoppingCrateSellFromSubList.BarScroll;
|
||||
bool hasPermissions = HasPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
|
||||
if ((storeRequestedSubGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
|
||||
{
|
||||
if (storeRequestedSubGoodGroup == null)
|
||||
{
|
||||
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellList);
|
||||
storeRequestedSubGoodGroup.Parent.SetAsFirstChild();
|
||||
}
|
||||
else
|
||||
{
|
||||
storeSellFromSubList.RemoveChild(storeRequestedSubGoodGroup.Parent);
|
||||
storeRequestedSubGoodGroup = null;
|
||||
}
|
||||
storeSellFromSubList.RecalculateChildren();
|
||||
}
|
||||
|
||||
foreach (PurchasedItem item in itemsToSellFromSub)
|
||||
{
|
||||
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
||||
}
|
||||
|
||||
foreach (var requestedGood in CurrentLocation.RequestedGoods)
|
||||
{
|
||||
if (itemsToSellFromSub.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
|
||||
CreateOrUpdateItemFrame(requestedGood, 0);
|
||||
}
|
||||
|
||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
|
||||
{
|
||||
PriceInfo priceInfo = itemPrefab.GetPriceInfo(CurrentLocation);
|
||||
if (priceInfo == null) { return; }
|
||||
var isRequestedGood = CurrentLocation.RequestedGoods.Contains(itemPrefab);
|
||||
var itemFrame = isRequestedGood ?
|
||||
storeRequestedSubGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||
storeSellFromSubList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
||||
if (CargoManager.ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInSellFromSubCrate)
|
||||
{
|
||||
itemQuantity = Math.Max(itemQuantity - itemInSellFromSubCrate.Quantity, 0);
|
||||
}
|
||||
if (itemFrame == null)
|
||||
{
|
||||
var parentComponent = isRequestedGood ? storeRequestedSubGoodGroup : storeSellFromSubList as GUIComponent;
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), parentComponent, StoreTab.SellFromSub, forceDisable: !hasPermissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = itemQuantity;
|
||||
SetQuantityLabelText(StoreTab.SellFromSub, itemFrame);
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetPriceGetters(itemFrame, false);
|
||||
}
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && itemQuantity > 0);
|
||||
if (itemQuantity < 1 && !isRequestedGood)
|
||||
{
|
||||
itemFrame.Visible = false;
|
||||
}
|
||||
existingItemFrames.Add(itemFrame);
|
||||
}
|
||||
|
||||
var removedItemFrames = storeSellFromSubList.Content.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList();
|
||||
if (storeRequestedSubGoodGroup != null)
|
||||
{
|
||||
removedItemFrames.AddRange(storeRequestedSubGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
|
||||
}
|
||||
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
|
||||
if (activeTab == StoreTab.SellFromSub) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.SellFromSub);
|
||||
|
||||
storeSellFromSubList.BarScroll = prevSellListScroll;
|
||||
shoppingCrateSellFromSubList.BarScroll = prevShoppingCrateScroll;
|
||||
}
|
||||
|
||||
private void SetPriceGetters(GUIComponent itemFrame, bool buying)
|
||||
{
|
||||
if (itemFrame == null || !(itemFrame.UserData is PurchasedItem pi)) { return; }
|
||||
@@ -834,11 +1006,41 @@ namespace Barotrauma
|
||||
needsItemsToSellRefresh = false;
|
||||
}
|
||||
|
||||
private void RefreshShoppingCrateList(List<PurchasedItem> items, GUIListBox listBox)
|
||||
public void RefreshItemsToSellFromSub()
|
||||
{
|
||||
itemsToSellFromSub.Clear();
|
||||
var subItems = CargoManager.GetSellableItemsFromSub();
|
||||
foreach (Item subItem in subItems)
|
||||
{
|
||||
if (itemsToSellFromSub.FirstOrDefault(i => i.ItemPrefab == subItem.Prefab) is PurchasedItem item)
|
||||
{
|
||||
item.Quantity += 1;
|
||||
}
|
||||
else if (subItem.Prefab.GetPriceInfo(CurrentLocation) != null)
|
||||
{
|
||||
itemsToSellFromSub.Add(new PurchasedItem(subItem.Prefab, 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove items from sell crate if they aren't on the sub anymore
|
||||
var itemsInCrate = new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate);
|
||||
foreach (PurchasedItem crateItem in itemsInCrate)
|
||||
{
|
||||
var subItem = itemsToSellFromSub.Find(i => i.ItemPrefab == crateItem.ItemPrefab);
|
||||
var subItemQuantity = subItem != null ? subItem.Quantity : 0;
|
||||
if (crateItem.Quantity > subItemQuantity)
|
||||
{
|
||||
CargoManager.ModifyItemQuantityInSellFromSubCrate(crateItem.ItemPrefab, subItemQuantity - crateItem.Quantity);
|
||||
}
|
||||
}
|
||||
sellableItemsFromSubUpdateTimer = 0.0f;
|
||||
needsItemsToSellFromSubRefresh = false;
|
||||
}
|
||||
|
||||
private void RefreshShoppingCrateList(List<PurchasedItem> items, GUIListBox listBox, StoreTab tab)
|
||||
{
|
||||
bool hasPermissions = HasPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
bool refreshingBuyList = listBox == shoppingCrateBuyList;
|
||||
int totalPrice = 0;
|
||||
foreach (PurchasedItem item in items)
|
||||
{
|
||||
@@ -849,7 +1051,7 @@ namespace Barotrauma
|
||||
GUINumberInput numInput = null;
|
||||
if (itemFrame == null)
|
||||
{
|
||||
itemFrame = CreateItemFrame(item, priceInfo, listBox, forceDisable: !hasPermissions);
|
||||
itemFrame = CreateItemFrame(item, listBox, tab, forceDisable: !hasPermissions);
|
||||
numInput = itemFrame.FindChild(c => c is GUINumberInput, recursive: true) as GUINumberInput;
|
||||
}
|
||||
else
|
||||
@@ -860,7 +1062,7 @@ namespace Barotrauma
|
||||
{
|
||||
numInput.UserData = item;
|
||||
numInput.Enabled = hasPermissions;
|
||||
numInput.MaxValueInt = GetMaxAvailable(item.ItemPrefab, refreshingBuyList ? StoreTab.Buy : StoreTab.Sell);
|
||||
numInput.MaxValueInt = GetMaxAvailable(item.ItemPrefab, tab);
|
||||
}
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetItemFrameStatus(itemFrame, hasPermissions);
|
||||
@@ -875,7 +1077,7 @@ namespace Barotrauma
|
||||
}
|
||||
suppressBuySell = false;
|
||||
|
||||
var price = refreshingBuyList ?
|
||||
var price = tab == StoreTab.Buy ?
|
||||
CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo) :
|
||||
CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
totalPrice += item.Quantity * price;
|
||||
@@ -885,24 +1087,32 @@ namespace Barotrauma
|
||||
removedItemFrames.ForEach(f => listBox.Content.RemoveChild(f));
|
||||
|
||||
SortItems(listBox, SortingMethod.CategoryAsc);
|
||||
listBox.UpdateScrollBarSize();
|
||||
if (refreshingBuyList)
|
||||
listBox.UpdateScrollBarSize();
|
||||
switch (tab)
|
||||
{
|
||||
buyTotal = totalPrice;
|
||||
if (IsBuying) { SetShoppingCrateTotalText(); }
|
||||
case StoreTab.Buy:
|
||||
buyTotal = totalPrice;
|
||||
break;
|
||||
case StoreTab.Sell:
|
||||
sellTotal = totalPrice;
|
||||
break;
|
||||
case StoreTab.SellFromSub:
|
||||
sellFromSubTotal = totalPrice;
|
||||
break;
|
||||
}
|
||||
else
|
||||
if (activeTab == tab)
|
||||
{
|
||||
sellTotal = totalPrice;
|
||||
if(IsSelling) { SetShoppingCrateTotalText(); }
|
||||
SetShoppingCrateTotalText();
|
||||
}
|
||||
SetClearAllButtonStatus();
|
||||
SetConfirmButtonStatus();
|
||||
}
|
||||
|
||||
private void RefreshShoppingCrateBuyList() => RefreshShoppingCrateList(CargoManager.ItemsInBuyCrate, shoppingCrateBuyList);
|
||||
private void RefreshShoppingCrateBuyList() => RefreshShoppingCrateList(CargoManager.ItemsInBuyCrate, shoppingCrateBuyList, StoreTab.Buy);
|
||||
|
||||
private void RefreshShoppingCrateSellList() => RefreshShoppingCrateList(CargoManager.ItemsInSellCrate, shoppingCrateSellList);
|
||||
private void RefreshShoppingCrateSellList() => RefreshShoppingCrateList(CargoManager.ItemsInSellCrate, shoppingCrateSellList, StoreTab.Sell);
|
||||
|
||||
private void RefreshShoppingCrateSellFromSubList() => RefreshShoppingCrateList(CargoManager.ItemsInSellFromSubCrate, shoppingCrateSellFromSubList, StoreTab.SellFromSub);
|
||||
|
||||
private void SortItems(GUIListBox list, SortingMethod sortingMethod)
|
||||
{
|
||||
@@ -934,7 +1144,7 @@ namespace Barotrauma
|
||||
else if (sortingMethod == SortingMethod.PriceAsc || sortingMethod == SortingMethod.PriceDesc)
|
||||
{
|
||||
SortItems(list, SortingMethod.AlphabeticalAsc);
|
||||
if (list == storeSellList || list == shoppingCrateSellList)
|
||||
if (list != storeBuyList && list != shoppingCrateBuyList)
|
||||
{
|
||||
list.Content.RectTransform.SortChildren(CompareBySellPrice);
|
||||
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
|
||||
@@ -1016,6 +1226,10 @@ namespace Barotrauma
|
||||
{
|
||||
return storeRequestedGoodGroup;
|
||||
}
|
||||
else if (list == storeSellFromSubList)
|
||||
{
|
||||
return storeRequestedSubGoodGroup;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
@@ -1047,15 +1261,20 @@ namespace Barotrauma
|
||||
|
||||
private void SortItems(StoreTab tab, SortingMethod sortingMethod)
|
||||
{
|
||||
if (IsTabUnavailable(tab)) { return; }
|
||||
tabSortingMethods[tab] = sortingMethod;
|
||||
SortItems(tabLists[tab], sortingMethod);
|
||||
}
|
||||
|
||||
private void SortItems(StoreTab tab) => SortItems(tab, tabSortingMethods[tab]);
|
||||
private void SortItems(StoreTab tab)
|
||||
{
|
||||
if (IsTabUnavailable(tab)) { return; }
|
||||
SortItems(tab, tabSortingMethods[tab]);
|
||||
}
|
||||
|
||||
private void SortActiveTabItems(SortingMethod sortingMethod) => SortItems(activeTab, sortingMethod);
|
||||
|
||||
private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIComponent parentComponent, bool forceDisable = false)
|
||||
private GUIComponent CreateItemFrame(PurchasedItem pi, GUIComponent parentComponent, StoreTab containingTab, bool forceDisable = false)
|
||||
{
|
||||
var tooltip = pi.ItemPrefab.Name;
|
||||
if (!string.IsNullOrWhiteSpace(pi.ItemPrefab.Description))
|
||||
@@ -1116,8 +1335,8 @@ namespace Barotrauma
|
||||
CanBeFocused = false,
|
||||
Stretch = true
|
||||
};
|
||||
var isSellingRelatedList = parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup || parentComponent == shoppingCrateSellList;
|
||||
var locationHasDealOnItem = isSellingRelatedList ?
|
||||
bool isSellingRelatedList = containingTab != StoreTab.Buy;
|
||||
bool locationHasDealOnItem = isSellingRelatedList ?
|
||||
CurrentLocation.RequestedGoods.Contains(pi.ItemPrefab) : CurrentLocation.DailySpecials.Contains(pi.ItemPrefab);
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), nameAndQuantityGroup.RectTransform),
|
||||
pi.ItemPrefab.Name, font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft)
|
||||
@@ -1142,14 +1361,15 @@ namespace Barotrauma
|
||||
};
|
||||
dealIcon.SetAsFirstChild();
|
||||
}
|
||||
var isParentOnLeftSideOfInterface = parentComponent == storeBuyList || parentComponent == storeDailySpecialsGroup ||
|
||||
parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup;
|
||||
bool isParentOnLeftSideOfInterface = parentComponent == storeBuyList || parentComponent == storeDailySpecialsGroup ||
|
||||
parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup ||
|
||||
parentComponent == storeSellFromSubList || parentComponent == storeRequestedSubGoodGroup;
|
||||
GUILayoutGroup shoppingCrateAmountGroup = null;
|
||||
GUINumberInput amountInput = null;
|
||||
if (isParentOnLeftSideOfInterface)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), nameAndQuantityGroup.RectTransform),
|
||||
CreateQuantityLabelText(isSellingRelatedList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
|
||||
CreateQuantityLabelText(containingTab, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Shadow = locationHasDealOnItem,
|
||||
@@ -1158,7 +1378,7 @@ namespace Barotrauma
|
||||
UserData = "quantitylabel"
|
||||
};
|
||||
}
|
||||
else if (!isParentOnLeftSideOfInterface)
|
||||
else
|
||||
{
|
||||
var relativePadding = nameBlock.Padding.X / nameBlock.Rect.Width;
|
||||
shoppingCrateAmountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativePadding, 0.6f), nameAndQuantityGroup.RectTransform) { RelativeOffset = new Vector2(relativePadding, 0) },
|
||||
@@ -1169,7 +1389,7 @@ namespace Barotrauma
|
||||
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), shoppingCrateAmountGroup.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, isSellingRelatedList ? StoreTab.Sell : StoreTab.Buy),
|
||||
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, containingTab),
|
||||
UserData = pi,
|
||||
IntValue = pi.Quantity
|
||||
};
|
||||
@@ -1396,7 +1616,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private string CreateQuantityLabelText(StoreTab mode, int quantity) => mode == StoreTab.Sell ?
|
||||
private string CreateQuantityLabelText(StoreTab mode, int quantity) => mode != StoreTab.Buy ?
|
||||
TextManager.GetWithVariable("campaignstore.quantity", "[amount]", quantity.ToString()) :
|
||||
TextManager.GetWithVariable("campaignstore.instock", "[amount]", quantity.ToString());
|
||||
|
||||
@@ -1419,10 +1639,16 @@ namespace Barotrauma
|
||||
|
||||
private int GetMaxAvailable(ItemPrefab itemPrefab, StoreTab mode)
|
||||
{
|
||||
var list = mode == StoreTab.Sell ? itemsToSell : CurrentLocation.StoreStock;
|
||||
var list = mode switch
|
||||
{
|
||||
StoreTab.Buy => CurrentLocation.StoreStock,
|
||||
StoreTab.Sell => itemsToSell,
|
||||
StoreTab.SellFromSub => itemsToSellFromSub,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
if (list.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem item)
|
||||
{
|
||||
if (mode != StoreTab.Sell)
|
||||
if (mode == StoreTab.Buy)
|
||||
{
|
||||
var purchasedItem = CargoManager.PurchasedItems.Find(i => i.ItemPrefab == item.ItemPrefab);
|
||||
if (purchasedItem != null) { return Math.Max(item.Quantity - purchasedItem.Quantity, 0); }
|
||||
@@ -1471,11 +1697,37 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool AddToShoppingCrate(PurchasedItem item, int quantity = 1) => IsBuying ?
|
||||
ModifyBuyQuantity(item, quantity) : ModifySellQuantity(item, quantity);
|
||||
private bool ModifySellFromSubQuantity(PurchasedItem item, int quantity)
|
||||
{
|
||||
if (item == null || item.ItemPrefab == null) { return false; }
|
||||
if (!HasPermissions) { return false; }
|
||||
if (quantity > 0)
|
||||
{
|
||||
// Make sure there's enough available to sell
|
||||
var itemToSell = CargoManager.ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == item.ItemPrefab);
|
||||
var totalQuantityToSell = itemToSell != null ? itemToSell.Quantity + quantity : quantity;
|
||||
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.SellFromSub)) { return false; }
|
||||
}
|
||||
CargoManager.ModifyItemQuantityInSellFromSubCrate(item.ItemPrefab, quantity);
|
||||
// TODO: GameMain.Client?.SendCampaignState();
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ClearFromShoppingCrate(PurchasedItem item) => IsBuying ?
|
||||
ModifyBuyQuantity(item, -item.Quantity) : ModifySellQuantity(item, -item.Quantity);
|
||||
private bool AddToShoppingCrate(PurchasedItem item, int quantity = 1) => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => ModifyBuyQuantity(item, quantity),
|
||||
StoreTab.Sell => ModifySellQuantity(item, quantity),
|
||||
StoreTab.SellFromSub => ModifySellFromSubQuantity(item, quantity),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
private bool ClearFromShoppingCrate(PurchasedItem item) => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => ModifyBuyQuantity(item, -item.Quantity),
|
||||
StoreTab.Sell => ModifySellQuantity(item, -item.Quantity),
|
||||
StoreTab.SellFromSub => ModifySellFromSubQuantity(item, -item.Quantity),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
private bool BuyItems()
|
||||
{
|
||||
@@ -1512,18 +1764,17 @@ namespace Barotrauma
|
||||
private bool SellItems()
|
||||
{
|
||||
if (!HasPermissions) { return false; }
|
||||
|
||||
var itemsToSell = new List<PurchasedItem>(CargoManager.ItemsInSellCrate);
|
||||
var itemsToSell = activeTab switch
|
||||
{
|
||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
||||
StoreTab.SellFromSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
var itemsToRemove = new List<PurchasedItem>();
|
||||
var totalValue = 0;
|
||||
foreach (PurchasedItem item in itemsToSell)
|
||||
{
|
||||
if (item?.ItemPrefab == null)
|
||||
{
|
||||
itemsToRemove.Add(item);
|
||||
continue;
|
||||
}
|
||||
if (item.ItemPrefab.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)
|
||||
if (item?.ItemPrefab?.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)
|
||||
{
|
||||
totalValue += item.Quantity * CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
}
|
||||
@@ -1533,12 +1784,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
itemsToRemove.ForEach(i => itemsToSell.Remove(i));
|
||||
|
||||
if (itemsToSell.None() || totalValue > CurrentLocation.StoreCurrentBalance) { return false; }
|
||||
|
||||
CargoManager.SellItems(itemsToSell);
|
||||
GameMain.Client?.SendCampaignState();
|
||||
|
||||
CargoManager.SellItems(itemsToSell, activeTab);
|
||||
if (activeTab == StoreTab.Sell)
|
||||
{
|
||||
// TODO: Implement selling sub items in multiplayer
|
||||
GameMain.Client?.SendCampaignState();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1551,8 +1803,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
shoppingCrateTotal.Text = GetCurrencyFormatted(sellTotal);
|
||||
shoppingCrateTotal.TextColor = CurrentLocation != null && sellTotal > CurrentLocation.StoreCurrentBalance ? Color.Red : Color.White;
|
||||
int total = activeTab switch
|
||||
{
|
||||
StoreTab.Sell => sellTotal,
|
||||
StoreTab.SellFromSub => sellFromSubTotal,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
shoppingCrateTotal.Text = GetCurrencyFormatted(total);
|
||||
shoppingCrateTotal.TextColor = CurrentLocation != null && total > CurrentLocation.StoreCurrentBalance ? Color.Red : Color.White;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1582,13 +1840,19 @@ namespace Barotrauma
|
||||
|
||||
private void SetConfirmButtonStatus() => confirmButton.Enabled =
|
||||
HasPermissions && ActiveShoppingCrateList.Content.RectTransform.Children.Any() &&
|
||||
((IsBuying && buyTotal <= PlayerMoney) || (IsSelling && CurrentLocation != null && sellTotal <= CurrentLocation.StoreCurrentBalance));
|
||||
activeTab switch
|
||||
{
|
||||
StoreTab.Buy => buyTotal <= PlayerMoney,
|
||||
StoreTab.Sell => CurrentLocation != null && sellTotal <= CurrentLocation.StoreCurrentBalance,
|
||||
StoreTab.SellFromSub => CurrentLocation != null && sellFromSubTotal <= CurrentLocation.StoreCurrentBalance,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
private void SetClearAllButtonStatus() => clearAllButton.Enabled =
|
||||
HasPermissions && ActiveShoppingCrateList.Content.RectTransform.Children.Any();
|
||||
|
||||
private float ownedItemsUpdateTimer = 0.0f;
|
||||
private readonly float ownedItemsUpdateInterval = 1.5f;
|
||||
private float ownedItemsUpdateTimer = 0.0f, sellableItemsFromSubUpdateTimer = 0.0f;
|
||||
private readonly float timerUpdateInterval = 1.5f;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
@@ -1600,7 +1864,7 @@ namespace Barotrauma
|
||||
{
|
||||
// Update the owned items at short intervals and check if the interface should be refreshed
|
||||
ownedItemsUpdateTimer += deltaTime;
|
||||
if (ownedItemsUpdateTimer >= ownedItemsUpdateInterval)
|
||||
if (ownedItemsUpdateTimer >= timerUpdateInterval)
|
||||
{
|
||||
var prevOwnedItems = new Dictionary<ItemPrefab, int>(OwnedItems);
|
||||
UpdateOwnedItems();
|
||||
@@ -1614,12 +1878,21 @@ namespace Barotrauma
|
||||
needsRefresh = true;
|
||||
}
|
||||
}
|
||||
// Update the sellable sub items at short intervals and check if the interface should be refreshed
|
||||
sellableItemsFromSubUpdateTimer += deltaTime;
|
||||
if (sellableItemsFromSubUpdateTimer >= timerUpdateInterval)
|
||||
{
|
||||
needsItemsToSellFromSubRefresh = true;
|
||||
needsRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsItemsToSellRefresh) { RefreshItemsToSell(); }
|
||||
if (needsItemsToSellFromSubRefresh) { RefreshItemsToSellFromSub(); }
|
||||
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
||||
if (needsBuyingRefresh) { RefreshBuying(); }
|
||||
if (needsSellingRefresh) { RefreshSelling(); }
|
||||
if (needsSellingFromSubRefresh) { RefreshSellingFromSub(updateItemsToSellFromSub: sellableItemsFromSubUpdateTimer > 0.0f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -42,10 +43,7 @@ namespace Barotrauma
|
||||
public IEnumerable<Item> GetSellableItems(Character character)
|
||||
{
|
||||
if (character == null) { return new List<Item>(); }
|
||||
// Only consider items which have been:
|
||||
// a) sold in singleplayer or confirmed by server (SellStatus.Confirmed); or
|
||||
// b) sold locally in multiplayer (SellStatus.Local), but the client has not received a campaing state update yet after selling them
|
||||
var confirmedSoldEntities = SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||
var confirmedSoldEntities = GetConfirmedSoldEntities();
|
||||
// The bag slot is intentionally left out since we want to be able to sell items from there
|
||||
var equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
|
||||
return character.Inventory.FindAllItems(item =>
|
||||
@@ -72,6 +70,43 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Item> GetSellableItemsFromSub()
|
||||
{
|
||||
if (Submarine.MainSub == null) { return new List<Item>(); }
|
||||
var confirmedSoldEntities = GetConfirmedSoldEntities();
|
||||
return Submarine.MainSub.GetItems(true).FindAll(item =>
|
||||
{
|
||||
if (!item.Prefab.CanBeSold) { return false; }
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (!item.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { return false; }
|
||||
if (!item.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { return false; }
|
||||
if (!ItemAndAllContainersInteractable(item)) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
// There must be no contained items or the contained items must be confirmed as sold
|
||||
if (!item.ContainedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
return true;
|
||||
}).Distinct();
|
||||
|
||||
static bool ItemAndAllContainersInteractable(Item item)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!item.IsPlayerTeamInteractable) { return false; }
|
||||
item = item.Container;
|
||||
} while (item != null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<SoldEntity> GetConfirmedSoldEntities()
|
||||
{
|
||||
// Only consider items which have been:
|
||||
// a) sold in singleplayer or confirmed by server (SellStatus.Confirmed); or
|
||||
// b) sold locally in multiplayer (SellStatus.Local), but the client has not received a campaing state update yet after selling them
|
||||
return SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||
}
|
||||
|
||||
public void SetItemsInBuyCrate(List<PurchasedItem> items)
|
||||
{
|
||||
ItemsInBuyCrate.Clear();
|
||||
@@ -119,10 +154,34 @@ namespace Barotrauma
|
||||
OnItemsInSellCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SellItems(List<PurchasedItem> itemsToSell)
|
||||
public void ModifyItemQuantityInSellFromSubCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
||||
{
|
||||
var itemsInInventory = GetSellableItems(Character.Controlled);
|
||||
var canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
|
||||
var itemToSell = ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == itemPrefab);
|
||||
if (itemToSell != null)
|
||||
{
|
||||
itemToSell.Quantity += changeInQuantity;
|
||||
if (itemToSell.Quantity < 1)
|
||||
{
|
||||
ItemsInSellFromSubCrate.Remove(itemToSell);
|
||||
}
|
||||
}
|
||||
else if (changeInQuantity > 0)
|
||||
{
|
||||
itemToSell = new PurchasedItem(itemPrefab, changeInQuantity);
|
||||
ItemsInSellFromSubCrate.Add(itemToSell);
|
||||
}
|
||||
OnItemsInSellFromSubCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SellItems(List<PurchasedItem> itemsToSell, Store.StoreTab sellingMode)
|
||||
{
|
||||
var sellableItems = sellingMode switch
|
||||
{
|
||||
Store.StoreTab.Sell => GetSellableItems(Character.Controlled),
|
||||
Store.StoreTab.SellFromSub => GetSellableItemsFromSub(),
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
bool canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
|
||||
var sellerId = GameMain.Client?.ID ?? 0;
|
||||
|
||||
// Check all the prices before starting the transaction
|
||||
@@ -137,7 +196,7 @@ namespace Barotrauma
|
||||
if (Location.StoreCurrentBalance < itemValue) { continue; }
|
||||
|
||||
// TODO: Write logic for prioritizing certain items over others (e.g. lone Battery Cell should be preferred over one inside a Stun Baton)
|
||||
var matchingItems = itemsInInventory.Where(i => i.Prefab == item.ItemPrefab);
|
||||
var matchingItems = sellableItems.Where(i => i.Prefab == item.ItemPrefab);
|
||||
if (matchingItems.Count() <= item.Quantity)
|
||||
{
|
||||
foreach (Item i in matchingItems)
|
||||
@@ -163,12 +222,21 @@ namespace Barotrauma
|
||||
campaign.Money += itemValue;
|
||||
|
||||
// Remove from the sell crate
|
||||
if (ItemsInSellCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } itemToSell)
|
||||
// TODO: Simplify duplicate logic?
|
||||
if (sellingMode == Store.StoreTab.Sell && ItemsInSellCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } inventoryItem)
|
||||
{
|
||||
itemToSell.Quantity -= item.Quantity;
|
||||
if (itemToSell.Quantity < 1)
|
||||
inventoryItem.Quantity -= item.Quantity;
|
||||
if (inventoryItem.Quantity < 1)
|
||||
{
|
||||
ItemsInSellCrate.Remove(itemToSell);
|
||||
ItemsInSellCrate.Remove(inventoryItem);
|
||||
}
|
||||
}
|
||||
else if(sellingMode == Store.StoreTab.SellFromSub && ItemsInSellFromSubCrate.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } subItem)
|
||||
{
|
||||
subItem.Quantity -= item.Quantity;
|
||||
if (subItem.Quantity < 1)
|
||||
{
|
||||
ItemsInSellFromSubCrate.Remove(subItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,17 +123,17 @@ namespace Barotrauma.Tutorials
|
||||
SetDoorAccess(tutorial_lockedDoor_2, null, false);
|
||||
|
||||
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: JobPrefab.Get("mechanic"));
|
||||
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "mechanic");
|
||||
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "mechanic");
|
||||
captain_mechanic.TeamID = CharacterTeamType.Team1;
|
||||
captain_mechanic.GiveJobItems();
|
||||
|
||||
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: JobPrefab.Get("securityofficer"));
|
||||
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "securityofficer");
|
||||
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "securityofficer");
|
||||
captain_security.TeamID = CharacterTeamType.Team1;
|
||||
captain_security.GiveJobItems();
|
||||
|
||||
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: JobPrefab.Get("engineer"));
|
||||
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "engineer");
|
||||
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "engineer");
|
||||
captain_engineer.TeamID = CharacterTeamType.Team1;
|
||||
captain_engineer.GiveJobItems();
|
||||
|
||||
|
||||
@@ -94,19 +94,19 @@ namespace Barotrauma.Tutorials
|
||||
patient2.AIController.Enabled = false;
|
||||
|
||||
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: JobPrefab.Get("engineer"));
|
||||
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job, Submarine.MainSub).WorldPosition, "3");
|
||||
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
|
||||
subPatient1.TeamID = CharacterTeamType.Team1;
|
||||
subPatient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 40.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient1);
|
||||
|
||||
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: JobPrefab.Get("securityofficer"));
|
||||
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job, Submarine.MainSub).WorldPosition, "3");
|
||||
var subPatient2 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
|
||||
subPatient2.TeamID = CharacterTeamType.Team1;
|
||||
subPatient2.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.InternalDamage, 40.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient2);
|
||||
|
||||
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: JobPrefab.Get("engineer"));
|
||||
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job, Submarine.MainSub).WorldPosition, "3");
|
||||
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
|
||||
subPatient3.TeamID = CharacterTeamType.Team1;
|
||||
subPatient3.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 20.0f) }, stun: 0, playSound: false);
|
||||
subPatients.Add(subPatient3);
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
|
||||
return WayPoint.GetRandom(spawnPointType, charInfo.Job, spawnSub);
|
||||
return WayPoint.GetRandom(spawnPointType, charInfo.Job?.Prefab, spawnSub);
|
||||
}
|
||||
|
||||
protected bool HasOrder(Character character, string identifier, string option = null)
|
||||
|
||||
@@ -1077,8 +1077,8 @@ namespace Barotrauma
|
||||
new RectTransform(new Vector2(0.5f, 1.0f), voiceInputContainerHorizontal.RectTransform),
|
||||
isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice"), font: GUI.SubHeadingFont);
|
||||
var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), voiceInputContainer.RectTransform, Anchor.TopRight), text: KeyBindText(InputType.Voice))
|
||||
var voiceKeybindLabel = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice"), font: GUI.SubHeadingFont);
|
||||
var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.3f, 1.0f), voiceInputContainer.RectTransform, Anchor.TopRight), text: KeyBindText(InputType.Voice))
|
||||
{
|
||||
SelectedColor = Color.Gold * 0.3f,
|
||||
UserData = InputType.Voice
|
||||
@@ -1089,14 +1089,16 @@ namespace Barotrauma
|
||||
new RectTransform(new Vector2(0.5f, 1.0f), voiceInputContainerHorizontal.RectTransform),
|
||||
isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), localVoiceInputContainer.RectTransform), TextManager.Get("InputType.LocalVoice"), font: GUI.SubHeadingFont);
|
||||
var localVoiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), localVoiceInputContainer.RectTransform, Anchor.TopRight), text: KeyBindText(InputType.LocalVoice))
|
||||
var localVoiceKeybindLabel = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), localVoiceInputContainer.RectTransform), TextManager.Get("InputType.LocalVoice"), font: GUI.SubHeadingFont);
|
||||
var localVoiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.3f, 1.0f), localVoiceInputContainer.RectTransform, Anchor.TopRight), text: KeyBindText(InputType.LocalVoice))
|
||||
{
|
||||
SelectedColor = Color.Gold * 0.3f,
|
||||
UserData = InputType.LocalVoice
|
||||
};
|
||||
localVoiceKeyBox.OnSelected += KeyBoxSelected;
|
||||
|
||||
voiceKeybindLabel.RectTransform.SizeChanged += () => { GUITextBlock.AutoScaleAndNormalize(voiceKeybindLabel, localVoiceKeybindLabel); };
|
||||
|
||||
var cutoffPreventionText = new GUITextBlock(new RectTransform(textBlockScale, voiceChatContent.RectTransform), TextManager.Get("CutoffPrevention"), font: GUI.SubHeadingFont)
|
||||
{
|
||||
ToolTip = TextManager.Get("CutoffPreventionTooltip")
|
||||
|
||||
@@ -7,13 +7,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
private void GetDamageModifierText(ref string description, float damageMultiplier, string afflictionIdentifier)
|
||||
{
|
||||
int roundedValue = (int)Math.Round((1 - damageMultiplier) * 100);
|
||||
if (roundedValue == 0) { return; }
|
||||
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||
description += $"\n ‖color:{colorStr}‖-{Math.Round((1 - damageMultiplier) * 100)}%‖color:end‖ {TextManager.Get("AfflictionName." + afflictionIdentifier, true) ?? afflictionIdentifier}";
|
||||
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("+0;-#")}%‖color:end‖ {TextManager.Get("AfflictionName." + afflictionIdentifier, true) ?? afflictionIdentifier}";
|
||||
}
|
||||
|
||||
public override void AddTooltipInfo(ref string description)
|
||||
{
|
||||
if (damageModifiers.Any(d => d.DamageMultiplier != 1f) || SkillModifiers.Any())
|
||||
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f)) || SkillModifiers.Any())
|
||||
{
|
||||
description += "\n";
|
||||
}
|
||||
@@ -22,7 +24,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (DamageModifier damageModifier in damageModifiers)
|
||||
{
|
||||
if (damageModifier.DamageMultiplier == 1f)
|
||||
if (MathUtils.NearlyEqual(damageModifier.DamageMultiplier, 1f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -42,7 +44,9 @@ namespace Barotrauma.Items.Components
|
||||
foreach (var skillModifier in SkillModifiers)
|
||||
{
|
||||
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||
description += $"\n ‖color:{colorStr}‖+{skillModifier.Value}‖color:end‖ {TextManager.Get("SkillName." + skillModifier.Key, true) ?? skillModifier.Key}";
|
||||
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, true) ?? skillModifier.Key}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +480,10 @@ namespace Barotrauma
|
||||
|
||||
if (IsSelected || IsHighlighted)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)), new Vector2(rect.Width, rect.Height),
|
||||
Vector2 drawPos = new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2));
|
||||
Vector2 drawSize = new Vector2(MathF.Ceiling(rect.Width + Math.Abs(drawPos.X - (int)drawPos.X)), MathF.Ceiling(rect.Height + Math.Abs(drawPos.Y - (int)drawPos.Y)));
|
||||
drawPos = new Vector2(MathF.Floor(drawPos.X), MathF.Floor(drawPos.Y));
|
||||
GUI.DrawRectangle(spriteBatch, drawPos, drawSize,
|
||||
Color.White, false, 0, thickness: Math.Max(1, (int)(2 / Screen.Selected.Cam.Zoom)));
|
||||
|
||||
foreach (Rectangle t in Prefab.Triggers)
|
||||
|
||||
@@ -527,7 +527,7 @@ namespace Barotrauma.Networking
|
||||
string pwMsg = TextManager.Get("PasswordRequired");
|
||||
|
||||
var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
|
||||
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, (int)(170 * Math.Max(1.0f, GUI.Scale))));
|
||||
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, GUI.IntScale(170)));
|
||||
var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
|
||||
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
|
||||
{
|
||||
@@ -537,7 +537,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (wrongPassword)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 0.33f), passwordHolder.RectTransform), TextManager.Language == "English" ? TextManager.Get("incorrectpassword") : "Incorrect password", GUI.Style.Red, GUI.Font, textAlignment: Alignment.Center);
|
||||
var incorrectPasswordText = new GUITextBlock(new RectTransform(new Vector2(1f, 0.0f), passwordHolder.RectTransform), TextManager.Get("incorrectpassword"), GUI.Style.Red, GUI.Font, textAlignment: Alignment.Center);
|
||||
incorrectPasswordText.RectTransform.MinSize = new Point(0, (int)incorrectPasswordText.TextSize.Y);
|
||||
passwordHolder.Recalculate();
|
||||
}
|
||||
|
||||
|
||||
@@ -469,18 +469,17 @@ namespace Barotrauma
|
||||
|
||||
this.game = game;
|
||||
|
||||
menuTabs[(int)Tab.Credits] = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null);
|
||||
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, menuTabs[(int)Tab.Credits].RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
|
||||
menuTabs[(int)Tab.Credits] = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, menuTabs[(int)Tab.Credits].RectTransform, Anchor.Center), style: "GUIBackgroundBlocker")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
var creditsContainer = new GUIFrame(new RectTransform(new Vector2(0.75f, 1.5f), menuTabs[(int)Tab.Credits].RectTransform, Anchor.CenterRight), style: "OuterGlow", color: Color.Black * 0.8f);
|
||||
creditsPlayer = new CreditsPlayer(new RectTransform(Vector2.One, creditsContainer.RectTransform), "Content/Texts/Credits.xml");
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 0.05f), menuTabs[(int)Tab.Credits].RectTransform, Anchor.BottomLeft) { RelativeOffset = new Vector2(0.25f, 0.02f) },
|
||||
TextManager.Get("Back"), style: "GUIButtonLarge")
|
||||
{
|
||||
OnClicked = SelectTab
|
||||
};
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1514,6 +1514,9 @@ namespace Barotrauma
|
||||
case SubmarineType.Wreck:
|
||||
contentType = ContentType.Wreck;
|
||||
break;
|
||||
case SubmarineType.EnemySubmarine:
|
||||
contentType = ContentType.EnemySubmarine;
|
||||
break;
|
||||
}
|
||||
if (contentType != ContentType.Submarine)
|
||||
{
|
||||
@@ -1829,7 +1832,12 @@ namespace Barotrauma
|
||||
subTypeContainer.RectTransform.MinSize = new Point(0, subTypeContainer.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
foreach (SubmarineType subType in Enum.GetValues(typeof(SubmarineType)))
|
||||
{
|
||||
subTypeDropdown.AddItem(TextManager.Get("submarinetype."+subType.ToString().ToLowerInvariant()), subType);
|
||||
string textTag = "SubmarineType." + subType;
|
||||
if (subType == SubmarineType.EnemySubmarine && !TextManager.ContainsTag(textTag))
|
||||
{
|
||||
textTag = "MissionType.Pirate";
|
||||
}
|
||||
subTypeDropdown.AddItem(TextManager.Get(textTag), subType);
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
@@ -2591,8 +2599,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (prevSub == null || prevSub.Type != sub.Type)
|
||||
{
|
||||
string textTag = "SubmarineType." + sub.Type;
|
||||
if (sub.Type == SubmarineType.EnemySubmarine && !TextManager.ContainsTag(textTag))
|
||||
{
|
||||
textTag = "MissionType.Pirate";
|
||||
}
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), subList.Content.RectTransform) { MinSize = new Point(0, 35) },
|
||||
TextManager.Get("SubmarineType." + sub.Type), font: GUI.LargeFont, textAlignment: Alignment.Center, style: "ListBoxElement")
|
||||
TextManager.Get(textTag), font: GUI.LargeFont, textAlignment: Alignment.Center, style: "ListBoxElement")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1400.2.0</Version>
|
||||
<Version>0.1400.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1400.2.0</Version>
|
||||
<Version>0.1400.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1400.2.0</Version>
|
||||
<Version>0.1400.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1400.2.0</Version>
|
||||
<Version>0.1400.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1400.2.0</Version>
|
||||
<Version>0.1400.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1400.2.0</Version>
|
||||
<Version>0.1400.3.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Barotrauma
|
||||
private float Sight => AIParams.Sight;
|
||||
private float Hearing => AIParams.Hearing;
|
||||
private float FleeHealthThreshold => AIParams.FleeHealthThreshold;
|
||||
private bool AggressiveBoarding => AIParams.AggressiveBoarding;
|
||||
private bool IsAggressiveBoarder => AIParams.AggressiveBoarding;
|
||||
|
||||
private FishAnimController FishAnimController => Character.AnimController as FishAnimController;
|
||||
|
||||
@@ -1271,7 +1271,7 @@ namespace Barotrauma
|
||||
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackingLimb.WorldPosition;
|
||||
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
||||
// Add a margin when the target is moving away, because otherwise it might be difficult to reach it if the attack takes some time to execute
|
||||
if (wallTarget != null)
|
||||
if (wallTarget != null && Character.Submarine == null)
|
||||
{
|
||||
if (wallTarget.Structure.Submarine != null)
|
||||
{
|
||||
@@ -1440,10 +1440,11 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
pathSteering.SteeringSeek(steerPos, 2, startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (Character.CurrentHull == null), checkVisiblity: true);
|
||||
// Switch to Idle when cannot reach the target and if cannot damage the walls
|
||||
if ((!canAttackWalls || wallTarget == null) && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
|
||||
if (!pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
|
||||
{
|
||||
State = AIState.Idle;
|
||||
IgnoreTarget(SelectedAiTarget);
|
||||
ResetAITarget();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1674,16 +1675,6 @@ namespace Barotrauma
|
||||
}
|
||||
if (canAttack)
|
||||
{
|
||||
if (SelectedAiTarget.Entity is Item targetItem)
|
||||
{
|
||||
var door = targetItem.GetComponent<Door>();
|
||||
if (door != null && door.CanBeTraversed)
|
||||
{
|
||||
ResetAITarget();
|
||||
State = PreviousState;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance, attackTargetLimb))
|
||||
{
|
||||
IgnoreTarget(SelectedAiTarget);
|
||||
@@ -2292,25 +2283,24 @@ namespace Barotrauma
|
||||
var section = s.Sections[i];
|
||||
if (section.gap == null) { continue; }
|
||||
bool leadsInside = !section.gap.IsRoomToRoom && section.gap.FlowTargetHull != null;
|
||||
isInnerWall = isInnerWall || !leadsInside;
|
||||
if (Character.AnimController.CanEnterSubmarine)
|
||||
{
|
||||
if (!isCharacterInside)
|
||||
{
|
||||
if (CanPassThroughHole(s, i))
|
||||
{
|
||||
valueModifier *= leadsInside ? (AggressiveBoarding ? 5 : 1) : 0;
|
||||
valueModifier *= leadsInside ? (IsAggressiveBoarder ? 3 : 1) : 0;
|
||||
}
|
||||
else if (AggressiveBoarding && leadsInside && canAttackWalls && AIParams.TargetOuterWalls)
|
||||
else if (IsAggressiveBoarder && leadsInside && canAttackWalls && AIParams.TargetOuterWalls)
|
||||
{
|
||||
// Up to 100% priority increase for every gap in the wall when an aggressive boarder is outside
|
||||
valueModifier *= 1 + section.gap.Open;
|
||||
// Up to 25% priority increase for every gap in the wall when an aggressive boarder is outside
|
||||
valueModifier *= 1 + section.gap.Open * 0.25f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inside
|
||||
if (AggressiveBoarding)
|
||||
if (IsAggressiveBoarder)
|
||||
{
|
||||
if (!isInnerWall)
|
||||
{
|
||||
@@ -2327,6 +2317,10 @@ namespace Barotrauma
|
||||
valueModifier = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
valueModifier = 0.1f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2350,7 +2344,7 @@ namespace Barotrauma
|
||||
valueModifier = 0;
|
||||
break;
|
||||
}
|
||||
else if (AggressiveBoarding)
|
||||
else if (IsAggressiveBoarder)
|
||||
{
|
||||
// Up to 100% priority increase for every gap in the wall when an aggressive boarder is outside
|
||||
// (Bonethreshers)
|
||||
@@ -2384,17 +2378,24 @@ namespace Barotrauma
|
||||
// Ignore broken and open doors, if cannot enter submarine
|
||||
continue;
|
||||
}
|
||||
if (AggressiveBoarding)
|
||||
if (IsAggressiveBoarder)
|
||||
{
|
||||
// Increase the priority if the character is outside and the door is from outside to inside
|
||||
if (character.CurrentHull == null)
|
||||
{
|
||||
valueModifier *= isOpen ? 5 : 1;
|
||||
// Increase the priority if the character is outside and the door is from outside to inside
|
||||
if (door.CanBeTraversed)
|
||||
{
|
||||
valueModifier = 3;
|
||||
}
|
||||
else if (door.LinkedGap != null)
|
||||
{
|
||||
valueModifier = 1 + door.LinkedGap.Open;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inside -> ignore open doors and outer doors
|
||||
valueModifier *= isOpen || isOutdoor ? 0 : 1;
|
||||
valueModifier = isOpen || isOutdoor ? 0 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2643,9 +2644,9 @@ namespace Barotrauma
|
||||
private void UpdateWallTarget(int requiredHoleCount)
|
||||
{
|
||||
wallTarget = null;
|
||||
if (AIParams.CanOpenDoors && HasValidPath(requireNonDirty: true)) { return; }
|
||||
if (SelectedAiTarget == null) { return; }
|
||||
if (SelectedAiTarget.Entity == null) { return; }
|
||||
if (HasValidPath(requireNonDirty: true)) { return; }
|
||||
wallHits.Clear();
|
||||
Structure wall = null;
|
||||
if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Target))
|
||||
@@ -2729,9 +2730,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (wall.NoAITarget && Character.AnimController.CanEnterSubmarine)
|
||||
{
|
||||
bool isTargetingDoor = SelectedAiTarget.Entity is Item i && i.GetComponent<Door>() != null;
|
||||
// Blocked by a wall that shouldn't be targeted. The main intention here is to prevent monsters from entering the the tail and the nose pieces.
|
||||
IgnoreTarget(SelectedAiTarget);
|
||||
ResetAITarget();
|
||||
if (!isTargetingDoor)
|
||||
{
|
||||
ResetAITarget();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2741,7 +2745,6 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
// Blocked by a disabled wall.
|
||||
IgnoreTarget(SelectedAiTarget);
|
||||
ResetAITarget();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1926,26 +1926,33 @@ namespace Barotrauma
|
||||
public static bool IsItemTargetedBySomeone(ItemComponent target, CharacterTeamType team, out Character operatingCharacter)
|
||||
{
|
||||
operatingCharacter = null;
|
||||
float highestPriority = -1.0f;
|
||||
float highestPriorityModifier = -1.0f;
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.Removed) { continue; }
|
||||
if (c.TeamID != team) { continue; }
|
||||
if (c.IsIncapacitated) { continue; }
|
||||
bool isOperated = c.SelectedConstruction == target.Item;
|
||||
if (!isOperated)
|
||||
{
|
||||
if (c.AIController is HumanAIController humanAI)
|
||||
{
|
||||
isOperated = humanAI.ObjectiveManager.Objectives.Any(o => o is AIObjectiveOperateItem operateObjective && operateObjective.Component.Item == target.Item);
|
||||
}
|
||||
}
|
||||
operatingCharacter = c;
|
||||
if (isOperated)
|
||||
if (c.SelectedConstruction == target.Item)
|
||||
{
|
||||
operatingCharacter = c;
|
||||
return true;
|
||||
}
|
||||
if (c.AIController is HumanAIController humanAI)
|
||||
{
|
||||
foreach (var objective in humanAI.ObjectiveManager.Objectives)
|
||||
{
|
||||
if (!(objective is AIObjectiveOperateItem operateObjective)) { continue; }
|
||||
if (operateObjective.Component.Item != target.Item) { continue; }
|
||||
if (operateObjective.Priority < highestPriority) { continue; }
|
||||
if (operateObjective.PriorityModifier < highestPriorityModifier) { continue; }
|
||||
operatingCharacter = c;
|
||||
highestPriority = operateObjective.Priority;
|
||||
highestPriorityModifier = operateObjective.PriorityModifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return operatingCharacter != null;
|
||||
}
|
||||
|
||||
// There's some duplicate logic in the two methods below, but making them use the same code would require some changes in the target classes so that we could use exactly the same checks.
|
||||
|
||||
@@ -637,7 +637,7 @@ namespace Barotrauma
|
||||
impactQueue.Enqueue(new Impact(f1, f2, contact, velocity));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return !f2.IsSensor;
|
||||
}
|
||||
|
||||
Vector2 colliderBottom = GetColliderBottom();
|
||||
@@ -1541,6 +1541,7 @@ namespace Barotrauma
|
||||
case Physics.CollisionLevel:
|
||||
if (!fixture.CollidesWith.HasFlag(Physics.CollisionCharacter)) { return -1; }
|
||||
if (fixture.Body.UserData is Submarine && character.Submarine != null) { return -1; }
|
||||
if (fixture.IsSensor) { return -1; }
|
||||
if (fraction < standOnFloorFraction)
|
||||
{
|
||||
standOnFloorFraction = fraction;
|
||||
|
||||
@@ -2377,6 +2377,10 @@ namespace Barotrauma
|
||||
var item = FindItemAtPosition(mouseSimPos, aimAssist);
|
||||
|
||||
focusedItem = CanInteract ? item : null;
|
||||
if (focusedItem != null && focusedItem.CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||
{
|
||||
FocusedCharacter = null;
|
||||
}
|
||||
findFocusedTimer = 0.05f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,17 @@ namespace Barotrauma
|
||||
|
||||
protected PropertyConditional.OperatorType Operator { get; set; }
|
||||
|
||||
public CheckDataAction(ScriptedEvent parentEvent, XElement element) : base(parentEvent, element) { }
|
||||
public CheckDataAction(ScriptedEvent parentEvent, XElement element) : base(parentEvent, element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Condition))
|
||||
{
|
||||
Condition = element.GetAttributeString("value", string.Empty);
|
||||
if (string.IsNullOrEmpty(Condition))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in scripted event \"{parentEvent.Prefab.Identifier}\". CheckDataAction with no condition set ({element}).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool? DetermineSuccess()
|
||||
{
|
||||
|
||||
@@ -213,7 +213,14 @@ namespace Barotrauma
|
||||
if (dialogOpened)
|
||||
{
|
||||
#if CLIENT
|
||||
Character.DisableControls = true;
|
||||
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "ConversationAction"))
|
||||
{
|
||||
Character.DisableControls = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
#endif
|
||||
if (ShouldInterrupt())
|
||||
{
|
||||
|
||||
@@ -20,11 +20,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ItemIdentifier))
|
||||
{
|
||||
ItemIdentifier = element.GetAttributeString("itemidentifiers", "");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(ItemIdentifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\" - RemoveItemAction without an item identifier.");
|
||||
ItemIdentifier = element.GetAttributeString("itemidentifiers", null) ?? element.GetAttributeString("identifier", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +62,7 @@ namespace Barotrauma
|
||||
var item = inventory.FindItem(it =>
|
||||
it != null &&
|
||||
!removedItems.Contains(it) &&
|
||||
it.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase), recursive: true);
|
||||
(string.IsNullOrEmpty(ItemIdentifier) || it.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase)), recursive: true);
|
||||
if (item == null) { break; }
|
||||
Entity.Spawner.AddToRemoveQueue(item);
|
||||
removedItems.Add(item);
|
||||
@@ -74,7 +70,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (target is Item item)
|
||||
{
|
||||
if (item.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(ItemIdentifier) || item.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
Entity.Spawner.AddToRemoveQueue(item);
|
||||
removedItems.Add(item);
|
||||
|
||||
@@ -128,8 +128,8 @@ namespace Barotrauma
|
||||
(speaker, player) => { if (e1 == speaker) { Trigger(speaker, player); } else { Trigger(player, speaker); } },
|
||||
TextManager.GetWithVariable("CampaignInteraction.Examine", "[key]", GameMain.Config.KeyBindText(InputType.Use)));
|
||||
#else
|
||||
npc.SetCustomInteract(
|
||||
Trigger,
|
||||
npc.SetCustomInteract(
|
||||
(speaker, player) => { if (e1 == speaker) { Trigger(speaker, player); } else { Trigger(player, speaker); } },
|
||||
TextManager.Get("CampaignInteraction.Talk"));
|
||||
GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||
#endif
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Barotrauma
|
||||
|
||||
if (element.Attribute("identifier") != null && element.Attribute("from") != null)
|
||||
{
|
||||
HumanPrefab humanPrefab = CreateHumanPrefabFromElement(element);
|
||||
HumanPrefab humanPrefab = GetHumanPrefabFromElement(element);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
LoadHuman(humanPrefab, element, submarine);
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma
|
||||
{
|
||||
this.sub = sub;
|
||||
itemConfig = prefab.ConfigElement.Element("Items");
|
||||
requiredDeliveryAmount = Math.Min(prefab.ConfigElement.GetAttributeFloat("requireddeliveryamount", 0.9f), 1.0f);
|
||||
requiredDeliveryAmount = Math.Min(prefab.ConfigElement.GetAttributeFloat("requireddeliveryamount", 0.98f), 1.0f);
|
||||
DetermineCargo();
|
||||
}
|
||||
|
||||
|
||||
@@ -84,8 +84,7 @@ namespace Barotrauma
|
||||
{
|
||||
characters.Clear();
|
||||
characterItems.Clear();
|
||||
// VIP transport mission characters stay in the same location; other characters roam at will
|
||||
// could be replaced with a designated waypoint for VIPs, such as cargo or crew
|
||||
|
||||
WayPoint explicitStayInHullPos = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
|
||||
Rand.RandSync randSync = Rand.RandSync.Server;
|
||||
|
||||
@@ -95,12 +94,30 @@ namespace Barotrauma
|
||||
randSync = Rand.RandSync.Unsynced;
|
||||
}
|
||||
|
||||
//if any of the escortees have a job defined, try to use a spawnpoint designated for that job
|
||||
foreach (XElement element in characterConfig.Elements())
|
||||
{
|
||||
var humanPrefab = GetHumanPrefabFromElement(element);
|
||||
if (humanPrefab == null || string.IsNullOrEmpty(humanPrefab.Job) || humanPrefab.Job.Equals("any", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
var jobPrefab = humanPrefab.GetJobPrefab();
|
||||
if (jobPrefab != null)
|
||||
{
|
||||
var jobSpecificSpawnPos = WayPoint.GetRandom(SpawnType.Human, jobPrefab, Submarine.MainSub);
|
||||
if (jobSpecificSpawnPos != null)
|
||||
{
|
||||
explicitStayInHullPos = jobSpecificSpawnPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (XElement element in characterConfig.Elements())
|
||||
{
|
||||
int count = CalculateScalingEscortedCharacterCount(inMission: true);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Character spawnedCharacter = CreateHuman(CreateHumanPrefabFromElement(element), characters, characterItems, Submarine.MainSub, CharacterTeamType.FriendlyNPC, explicitStayInHullPos, humanPrefabRandSync: randSync);
|
||||
Character spawnedCharacter = CreateHuman(GetHumanPrefabFromElement(element), characters, characterItems, Submarine.MainSub, CharacterTeamType.FriendlyNPC, explicitStayInHullPos, humanPrefabRandSync: randSync);
|
||||
if (spawnedCharacter.AIController is HumanAIController humanAI)
|
||||
{
|
||||
humanAI.InitMentalStateManager();
|
||||
|
||||
@@ -293,6 +293,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private void TryTriggerEvent(MissionPrefab.TriggerEvent trigger)
|
||||
{
|
||||
if (trigger.CampaignOnly && GameMain.GameSession?.Campaign == null) { return; }
|
||||
if (trigger.Delay > 0)
|
||||
{
|
||||
if (!delayedTriggerEvents.Any(t => t.TriggerEvent == trigger))
|
||||
@@ -311,6 +312,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private void TriggerEvent(MissionPrefab.TriggerEvent trigger)
|
||||
{
|
||||
if (trigger.CampaignOnly && GameMain.GameSession?.Campaign == null) { return; }
|
||||
var eventPrefab = EventSet.GetAllEventPrefabs().Find(p => p.Identifier.Equals(trigger.EventIdentifier, StringComparison.OrdinalIgnoreCase));
|
||||
if (eventPrefab == null)
|
||||
{
|
||||
@@ -398,7 +400,7 @@ namespace Barotrauma
|
||||
public virtual void AdjustLevelData(LevelData levelData) { }
|
||||
|
||||
// putting these here since both escort and pirate missions need them. could be tucked away into another class that they can inherit from (or use composition)
|
||||
protected HumanPrefab CreateHumanPrefabFromElement(XElement element)
|
||||
protected HumanPrefab GetHumanPrefabFromElement(XElement element)
|
||||
{
|
||||
if (element.Attribute("name") != null)
|
||||
{
|
||||
|
||||
@@ -117,6 +117,9 @@ namespace Barotrauma
|
||||
[Serialize(0.0f, true)]
|
||||
public float Delay { get; private set; }
|
||||
|
||||
[Serialize(false, true)]
|
||||
public bool CampaignOnly { get; private set; }
|
||||
|
||||
public TriggerEvent(XElement element)
|
||||
{
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
@@ -191,6 +191,8 @@ namespace Barotrauma
|
||||
}
|
||||
enemySub.EnableMaintainPosition();
|
||||
enemySub.TeamID = CharacterTeamType.None;
|
||||
//make the enemy sub withstand atleast the same depth as the player sub
|
||||
enemySub.RealWorldCrushDepth = Math.Max(enemySub.RealWorldCrushDepth, Submarine.MainSub.RealWorldCrushDepth);
|
||||
}
|
||||
|
||||
private void InitPirates()
|
||||
@@ -230,7 +232,7 @@ namespace Barotrauma
|
||||
|
||||
XElement variantElement = GetRandomDifficultyModifiedElement(characterType, enemyCreationDifficulty, RandomnessModifier);
|
||||
|
||||
Character spawnedCharacter = CreateHuman(CreateHumanPrefabFromElement(variantElement), characters, characterItems, enemySub, CharacterTeamType.None, null);
|
||||
Character spawnedCharacter = CreateHuman(GetHumanPrefabFromElement(variantElement), characters, characterItems, enemySub, CharacterTeamType.None, null);
|
||||
if (!commanderAssigned)
|
||||
{
|
||||
bool isCommander = variantElement.GetAttributeBool("iscommander", false);
|
||||
|
||||
@@ -431,7 +431,15 @@ namespace Barotrauma
|
||||
float scatterAmount = scatter;
|
||||
if (spawnPosType.HasFlag(Level.PositionType.SidePath))
|
||||
{
|
||||
scatterAmount = Math.Min(scatter, Level.Loaded.Tunnels.Where(t => t.Type == Level.TunnelType.SidePath).Min(t => t.MinWidth) / 2);
|
||||
var sidePaths = Level.Loaded.Tunnels.Where(t => t.Type == Level.TunnelType.SidePath);
|
||||
if (sidePaths.Any())
|
||||
{
|
||||
scatterAmount = Math.Min(scatter, sidePaths.Min(t => t.MinWidth) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
scatterAmount = scatter;
|
||||
}
|
||||
}
|
||||
else if (!spawnPosType.HasFlag(Level.PositionType.MainPath))
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Barotrauma
|
||||
|
||||
public List<PurchasedItem> ItemsInBuyCrate { get; } = new List<PurchasedItem>();
|
||||
public List<PurchasedItem> ItemsInSellCrate { get; } = new List<PurchasedItem>();
|
||||
public List<PurchasedItem> ItemsInSellFromSubCrate { get; } = new List<PurchasedItem>();
|
||||
public List<PurchasedItem> PurchasedItems { get; } = new List<PurchasedItem>();
|
||||
public List<SoldItem> SoldItems { get; } = new List<SoldItem>();
|
||||
|
||||
@@ -55,6 +56,7 @@ namespace Barotrauma
|
||||
|
||||
public Action OnItemsInBuyCrateChanged;
|
||||
public Action OnItemsInSellCrateChanged;
|
||||
public Action OnItemsInSellFromSubCrateChanged;
|
||||
public Action OnPurchasedItemsChanged;
|
||||
public Action OnSoldItemsChanged;
|
||||
|
||||
@@ -75,6 +77,12 @@ namespace Barotrauma
|
||||
OnItemsInSellCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ClearItemsInSellFromSubCrate()
|
||||
{
|
||||
ItemsInSellFromSubCrate.Clear();
|
||||
OnItemsInSellFromSubCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SetPurchasedItems(List<PurchasedItem> items)
|
||||
{
|
||||
PurchasedItems.Clear();
|
||||
|
||||
@@ -417,7 +417,7 @@ namespace Barotrauma
|
||||
if (isControlledCharacterNull) { return null; }
|
||||
#endif
|
||||
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemTargetedBySomeone(order.TargetItemComponent, controlledCharacter != null ? controlledCharacter.TeamID : CharacterTeamType.Team1, out Character operatingCharacter) &&
|
||||
(isControlledCharacterNull || operatingCharacter.CanHearCharacter(controlledCharacter)))
|
||||
(isControlledCharacterNull || operatingCharacter.CanHearCharacter(controlledCharacter)))
|
||||
{
|
||||
return operatingCharacter;
|
||||
}
|
||||
|
||||
@@ -558,12 +558,14 @@ namespace Barotrauma
|
||||
{
|
||||
CargoManager.ClearItemsInBuyCrate();
|
||||
CargoManager.ClearItemsInSellCrate();
|
||||
CargoManager.ClearItemsInSellFromSubCrate();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
CargoManager?.ClearItemsInBuyCrate();
|
||||
// TODO: CargoManager?.ClearItemsInSellFromSubCrate();
|
||||
}
|
||||
else if (GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class MotionSensor : ItemComponent
|
||||
{
|
||||
private const float UpdateInterval = 0.1f;
|
||||
private float rangeX, rangeY;
|
||||
|
||||
private Vector2 detectOffset;
|
||||
@@ -75,6 +74,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
[Editable(MinValueFloat = 0.1f, MaxValueFloat = 100.0f, DecimalCount = 2), Serialize(0.1f, true, description: "How often the sensor checks if there's something moving near it. Higher values are better for performance.", alwaysUseInstanceValues: true)]
|
||||
public float UpdateInterval
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private int maxOutputLength;
|
||||
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
|
||||
public int MaxOutputLength
|
||||
@@ -135,6 +141,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
rangeX = rangeY = element.GetAttributeFloat("range", 0.0f);
|
||||
}
|
||||
|
||||
//randomize update timer so all sensors aren't updated during the same frame
|
||||
updateTimer = Rand.Range(0.0f, UpdateInterval);
|
||||
}
|
||||
|
||||
public override void Load(XElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Barotrauma
|
||||
public readonly string Identifier;
|
||||
public readonly int OriginalContainerIndex;
|
||||
|
||||
public TakenItem(string identifier, UInt16 originalID, UInt16 originalContainerIndex, ushort moduleIndex)
|
||||
public TakenItem(string identifier, UInt16 originalID, int originalContainerIndex, ushort moduleIndex)
|
||||
{
|
||||
OriginalID = originalID;
|
||||
OriginalContainerIndex = originalContainerIndex;
|
||||
@@ -345,7 +345,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError($"Error in saved location: could not parse taken item id \"{takenItemSplit[1]}\"");
|
||||
continue;
|
||||
}
|
||||
if (!ushort.TryParse(takenItemSplit[2], out ushort containerIndex))
|
||||
if (!int.TryParse(takenItemSplit[2], out int containerIndex))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in saved location: could not parse taken container index \"{takenItemSplit[2]}\"");
|
||||
continue;
|
||||
@@ -577,6 +577,10 @@ namespace Barotrauma
|
||||
{
|
||||
weight /= missionCount * 2;
|
||||
}
|
||||
if (destination.IsRadiated())
|
||||
{
|
||||
weight *= 0.001f;
|
||||
}
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,16 @@ namespace Barotrauma
|
||||
//dimensions of the wall sections' physics bodies (only used for debug rendering)
|
||||
private readonly List<Vector2> bodyDebugDimensions = new List<Vector2>();
|
||||
|
||||
public bool Indestructible;
|
||||
#if DEBUG
|
||||
[Serialize(false, true), Editable]
|
||||
#else
|
||||
[Serialize(false, true)]
|
||||
#endif
|
||||
public bool Indestructible
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
//sections of the wall that are supposed to be rendered
|
||||
public WallSection[] Sections
|
||||
@@ -798,7 +807,7 @@ namespace Barotrauma
|
||||
|
||||
public void AddDamage(int sectionIndex, float damage, Character attacker = null)
|
||||
{
|
||||
if (!Prefab.Body || Prefab.Platform || Indestructible ) { return; }
|
||||
if (!Prefab.Body || Prefab.Platform || Indestructible) { return; }
|
||||
|
||||
if (sectionIndex < 0 || sectionIndex > Sections.Length - 1) { return; }
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Barotrauma
|
||||
HideInMenus = 2
|
||||
}
|
||||
|
||||
public enum SubmarineType { Player, Outpost, OutpostModule, Wreck, BeaconStation }
|
||||
public enum SubmarineType { Player, Outpost, OutpostModule, Wreck, BeaconStation, EnemySubmarine }
|
||||
public enum SubmarineClass { Undefined, Scout, Attack, Transport, DeepDiver }
|
||||
|
||||
partial class SubmarineInfo : IDisposable
|
||||
|
||||
@@ -766,14 +766,14 @@ namespace Barotrauma
|
||||
if (!wayPoint2.linkedTo.Contains(this)) { wayPoint2.linkedTo.Add(this); }
|
||||
}
|
||||
|
||||
public static WayPoint GetRandom(SpawnType spawnType = SpawnType.Human, Job assignedJob = null, Submarine sub = null, Ruin ruin = null, bool useSyncedRand = false)
|
||||
public static WayPoint GetRandom(SpawnType spawnType = SpawnType.Human, JobPrefab assignedJob = null, Submarine sub = null, Ruin ruin = null, bool useSyncedRand = false)
|
||||
{
|
||||
return WayPointList.GetRandom(wp =>
|
||||
wp.Submarine == sub &&
|
||||
wp.ParentRuin == ruin &&
|
||||
wp.spawnType == spawnType &&
|
||||
(assignedJob == null || (assignedJob != null && wp.AssignedJob == assignedJob.Prefab))
|
||||
, useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced);
|
||||
(assignedJob == null || (assignedJob != null && wp.AssignedJob == assignedJob)),
|
||||
useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced);
|
||||
}
|
||||
|
||||
public static WayPoint[] SelectCrewSpawnPoints(List<CharacterInfo> crew, Submarine submarine)
|
||||
|
||||
BIN
Barotrauma/BarotraumaShared/Submarines/DugongPirate.sub
Normal file
BIN
Barotrauma/BarotraumaShared/Submarines/DugongPirate.sub
Normal file
Binary file not shown.
Binary file not shown.
BIN
Barotrauma/BarotraumaShared/Submarines/HumpbackPirate.sub
Normal file
BIN
Barotrauma/BarotraumaShared/Submarines/HumpbackPirate.sub
Normal file
Binary file not shown.
BIN
Barotrauma/BarotraumaShared/Submarines/Typhon2Pirate.sub
Normal file
BIN
Barotrauma/BarotraumaShared/Submarines/Typhon2Pirate.sub
Normal file
Binary file not shown.
@@ -1,3 +1,33 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.1400.3.0 (unstable)
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Changes:
|
||||
- Increased the health of the hammerhead mission variants to match the previous buff of the default characters.
|
||||
- Made it possible to sell items on the sub through a new store tab in singleplayer.
|
||||
- Miscellaneous improvements and fixes to the new scripted events.
|
||||
- Allow clicking on the main menu buttons when the credits are open.
|
||||
- Added a dummy lightcomponent to turret hardpoints to make it possible to adjust the properties of the lights that will be installed on the hardpoint.
|
||||
- Option to adjust motion sensor's update interval in the sub editor.
|
||||
- Display pirate subs in a separate category in the sub editor.
|
||||
- Escortees spawn at a spawnpoint suitable for their job if one is found. Shouldn't have an effect in the vanilla subs because they don't have specific spawnpoints for the escortees' jobs.
|
||||
|
||||
Fixes:
|
||||
- Fixed pirate subs getting crushed by pressure in levels later in the campaign.
|
||||
- Hide the event variant of the psychosis artifact in the sub editor.
|
||||
- Fixed less suitable characters getting quick-assigned for an order (e.g. captain getting assigned the "operate reactor" order).
|
||||
- Fixed missions sometimes unlocking in paths leading to an irradiated location even if there's a more suitable path available.
|
||||
- Fixed some campaign-specific scripted events triggering in abandoned outposts in the mission mode.
|
||||
- Fixed mudraptors no longer targeting doors.
|
||||
- Fixed white rectangle around selected items in the sub editor being slightly off if the item's position/size is not a whole number.
|
||||
- Fixed "incorrect password" text overlapping with the buttons in the password prompt.
|
||||
- Fixed "could not parse taken container index" error when stealing items that didn't spawn in a container in an outpost and returning to that outpost.
|
||||
- Fixed z-fighting in Medium Weapons Display Case.
|
||||
- Fixed inability to drop through broken hatches.
|
||||
- Fixed sprite bleed in IC-4 block's inventory icon.
|
||||
- Fixed damage modifiers in item tooltips always starting with a minus sign even if the modifier is positive, and skill modifiers always starting with "+".
|
||||
- Fixed healthbar and affliction area being clickable even if there's an UI element in front of them, and even if there's no afflictions in the affliction area. Most noticeable when editing an electrical components properties.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.1400.2.0 (unstable)
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user