Unstable 0.1400.7.0 (Coronavirus edition)
This commit is contained in:
@@ -479,7 +479,7 @@ namespace Barotrauma
|
||||
{
|
||||
CalculateLimbDepths();
|
||||
var controller = character.SelectedConstruction?.GetComponent<Controller>();
|
||||
if (controller != null && controller.ControlCharacterPose && controller.User == character)
|
||||
if (controller != null && controller.ControlCharacterPose && controller.User == character && controller.UserInCorrectPosition)
|
||||
{
|
||||
if (controller.Item.SpriteDepth <= maxDepth || controller.DrawUserBehind)
|
||||
{
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Barotrauma
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen)
|
||||
{
|
||||
if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null)
|
||||
if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null && Screen.Selected != GameMain.SubEditorScreen)
|
||||
{
|
||||
bool mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && GUI.MouseOn == null;
|
||||
if (mouseOnPortrait && PlayerInput.PrimaryMouseButtonClicked())
|
||||
@@ -391,7 +391,7 @@ namespace Barotrauma
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
||||
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
||||
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, npc.CurrentHull == Character.Controlled.CurrentHull ? 500.0f : 100.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
||||
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, npc.CurrentHull == character.CurrentHull ? 500.0f : 100.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -405,17 +405,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (character.SelectedConstruction != null &&
|
||||
(character.CanInteractWith(Character.Controlled.SelectedConstruction) || Screen.Selected == GameMain.SubEditorScreen))
|
||||
(character.CanInteractWith(character.SelectedConstruction) || Screen.Selected == GameMain.SubEditorScreen))
|
||||
{
|
||||
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
character.SelectedConstruction.DrawHUD(spriteBatch, cam, character);
|
||||
}
|
||||
if (Character.Controlled.Inventory != null)
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
foreach (Item item in Character.Controlled.Inventory.AllItems)
|
||||
foreach (Item item in character.Inventory.AllItems)
|
||||
{
|
||||
if (Character.Controlled.HasEquippedItem(item))
|
||||
if (character.HasEquippedItem(item))
|
||||
{
|
||||
item.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
item.DrawHUD(spriteBatch, cam, character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,6 +641,8 @@ namespace Barotrauma
|
||||
commands.Add(new Command("wikiimage_sub", "Save an image of the main submarine with a transparent background.", (string[] args) =>
|
||||
{
|
||||
if (Submarine.MainSub == null) { return; }
|
||||
MapEntity.SelectedList.Clear();
|
||||
MapEntity.mapEntityList.ForEach(me => me.IsHighlighted = false);
|
||||
WikiImage.Create(Submarine.MainSub);
|
||||
}));
|
||||
|
||||
|
||||
@@ -741,7 +741,6 @@ namespace Barotrauma
|
||||
{
|
||||
float diff = isHorizontal ? scrollToElement.Rect.X - Content.Rect.X : scrollToElement.Rect.Y - Content.Rect.Y;
|
||||
float speed = MathHelper.Clamp(Math.Abs(diff) * 0.1f, 5.0f, 100.0f);
|
||||
System.Diagnostics.Debug.WriteLine(speed);
|
||||
if (Math.Abs(diff) < speed || GUIScrollBar.DraggingBar != null)
|
||||
{
|
||||
speed = Math.Abs(diff);
|
||||
|
||||
@@ -259,7 +259,11 @@ namespace Barotrauma
|
||||
|
||||
public StrikethroughSettings Strikethrough = null;
|
||||
|
||||
public readonly List<RichTextData> RichTextData = null;
|
||||
public List<RichTextData> RichTextData
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool HasColorHighlight => RichTextData != null;
|
||||
|
||||
@@ -334,6 +338,12 @@ namespace Barotrauma
|
||||
if (wrappedText == null) { return; }
|
||||
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText, removeExtraSpacing).Y + padding));
|
||||
}
|
||||
|
||||
public void SetRichText(string richText)
|
||||
{
|
||||
RichTextData = Barotrauma.RichTextData.GetRichTextData(richText, out string sanitizedText);
|
||||
Text = sanitizedText;
|
||||
}
|
||||
|
||||
public override void ApplyStyle(GUIComponentStyle componentStyle)
|
||||
{
|
||||
@@ -485,7 +495,7 @@ namespace Barotrauma
|
||||
for (int j = 0; j <= line.Length; j++)
|
||||
{
|
||||
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j)) * textScale;
|
||||
Vector2 indexPos = new Vector2(lineTextSize.X + Padding.X, totalTextHeight + Padding.Y - halfHeight);
|
||||
Vector2 indexPos = new Vector2(lineTextSize.X, totalTextHeight - halfHeight) + TextPos - Origin * textScale;
|
||||
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
|
||||
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
|
||||
}
|
||||
@@ -498,7 +508,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i <= Text.Length; i++)
|
||||
{
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i)) * textScale;
|
||||
Vector2 indexPos = new Vector2(textSize.X + Padding.X, textSize.Y + Padding.Y - halfHeight) + TextPos - Origin * textScale;
|
||||
Vector2 indexPos = new Vector2(textSize.X, textSize.Y - halfHeight) + TextPos - Origin * textScale;
|
||||
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
|
||||
positions.Add(new Tuple<Vector2, int>(indexPos, i));
|
||||
}
|
||||
|
||||
@@ -1131,7 +1131,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
var sortResult = itemX.ItemPrefab.Name.CompareTo(itemY.ItemPrefab.Name);
|
||||
int sortResult = itemX.ItemPrefab.Name != itemY.ItemPrefab.Name ?
|
||||
itemX.ItemPrefab.Name.CompareTo(itemY.ItemPrefab.Name) :
|
||||
itemX.ItemPrefab.Identifier.CompareTo(itemY.ItemPrefab.Identifier);
|
||||
if (sortingMethod == SortingMethod.AlphabeticalDesc) { sortResult *= -1; }
|
||||
return sortResult;
|
||||
}
|
||||
|
||||
@@ -824,25 +824,34 @@ namespace Barotrauma
|
||||
currentUpgradeCategory = category;
|
||||
var entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true) && !i.HiddenInGame && i.AllowSwapping && i.Prefab.SwappableItem != null && category.ItemTags.Any(t => i.HasTag(t))).ToList();
|
||||
|
||||
int slotIndex = 0;
|
||||
foreach (Item item in entitiesOnSub)
|
||||
{
|
||||
slotIndex++;
|
||||
CreateSwappableItemSlideDown(parent, slotIndex, item, submarine);
|
||||
CreateSwappableItemSlideDown(parent, item, entitiesOnSub, submarine);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSwappableItemSlideDown(GUIListBox parent, int slotIndex, Item item, Submarine submarine)
|
||||
private void CreateSwappableItemSlideDown(GUIListBox parent, Item item, List<Item> swappableEntities, Submarine submarine)
|
||||
{
|
||||
if (Campaign == null || submarine == null) { return; }
|
||||
|
||||
IEnumerable<ItemPrefab> availableReplacements = MapEntityPrefab.List.Where(p =>
|
||||
p is ItemPrefab itemPrefab &&
|
||||
itemPrefab.SwappableItem != null &&
|
||||
itemPrefab.SwappableItem.CanBeBought &&
|
||||
itemPrefab.SwappableItem.CanBeBought &&
|
||||
itemPrefab.SwappableItem.SwapIdentifier.Equals(item.Prefab.SwappableItem.SwapIdentifier, StringComparison.OrdinalIgnoreCase)).Cast<ItemPrefab>();
|
||||
|
||||
var linkedItems = Campaign.UpgradeManager.GetLinkedItemsToSwap(item) ?? new List<Item>() { item };
|
||||
//create the swap entry only for one of the items (the one with the smallest ID)
|
||||
if (linkedItems.Min(it => it.ID) < item.ID) { return; }
|
||||
|
||||
var currentOrPending = item.PendingItemSwap ?? item.Prefab;
|
||||
string name = currentOrPending.Name;
|
||||
string quantityText = "";
|
||||
if (linkedItems.Count > 1)
|
||||
{
|
||||
quantityText = " " + TextManager.GetWithVariable("campaignstore.quantity", "[amount]", (linkedItems.Count).ToString());
|
||||
name += quantityText;
|
||||
}
|
||||
|
||||
bool isOpen = false;
|
||||
GUIButton toggleButton = new GUIButton(rectT(1f, 0.1f, parent.Content), text: string.Empty, style: "SlideDown")
|
||||
@@ -850,10 +859,21 @@ namespace Barotrauma
|
||||
UserData = item
|
||||
};
|
||||
GUILayoutGroup buttonLayout = new GUILayoutGroup(rectT(1f, 1f, toggleButton.Frame), isHorizontal: true);
|
||||
new GUITextBlock(rectT(0.3f, 1f, buttonLayout), text: TextManager.GetWithVariable("weaponslot", "[number]", slotIndex.ToString()), font: GUI.SubHeadingFont);
|
||||
|
||||
string slotText = "";
|
||||
if (linkedItems.Count > 1)
|
||||
{
|
||||
slotText = TextManager.GetWithVariable("weaponslot", "[number]", string.Join(", ", linkedItems.Select(it => (swappableEntities.IndexOf(it) + 1).ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
slotText = TextManager.GetWithVariable("weaponslot", "[number]", (swappableEntities.IndexOf(item) + 1).ToString());
|
||||
}
|
||||
|
||||
new GUITextBlock(rectT(0.3f, 1f, buttonLayout), text: slotText, font: GUI.SubHeadingFont);
|
||||
GUILayoutGroup group = new GUILayoutGroup(rectT(0.7f, 1f, buttonLayout), isHorizontal: true) { Stretch = true };
|
||||
|
||||
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", currentOrPending.Name) : item.Name;
|
||||
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : (linkedItems.Count > 1 ? item.Name + quantityText : item.Name);
|
||||
GUITextBlock text = new GUITextBlock(rectT(0.7f, 1f, group), text: title, font: GUI.SubHeadingFont, textAlignment: Alignment.Right, parseRichText: true)
|
||||
{
|
||||
TextColor = GUI.Style.Orange
|
||||
@@ -876,7 +896,7 @@ namespace Barotrauma
|
||||
if (isUninstallPending) { canUninstall = false; }
|
||||
|
||||
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
||||
TextManager.GetWithVariable(item.PendingItemSwap != null ? "upgrades.pendingitem" : "upgrades.installeditem", "[itemname]", currentOrPending.Name),
|
||||
TextManager.GetWithVariable(item.PendingItemSwap != null ? "upgrades.pendingitem" : "upgrades.installeditem", "[itemname]", name),
|
||||
currentOrPending.Description,
|
||||
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "WeaponUninstallButton"));
|
||||
|
||||
@@ -915,7 +935,7 @@ namespace Barotrauma
|
||||
|
||||
bool isPurchased = item.AvailableSwaps.Contains(replacement);
|
||||
|
||||
int price = isPurchased || replacement == item.Prefab ? 0 : replacement.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation);
|
||||
int price = isPurchased || replacement == item.Prefab ? 0 : replacement.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation) * linkedItems.Count;
|
||||
|
||||
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), replacement.UpgradePreviewSprite, replacement.Name, replacement.Description,
|
||||
price, replacement,
|
||||
@@ -931,7 +951,7 @@ namespace Barotrauma
|
||||
{
|
||||
string promptBody = TextManager.GetWithVariables(isPurchased ? "upgrades.itemswappromptbody" : "upgrades.purchaseitemswappromptbody",
|
||||
new[] { "[itemtoinstall]", "[amount]" },
|
||||
new[] { replacement.Name, replacement.SwappableItem.GetPrice(Campaign?.Map?.CurrentLocation).ToString() });
|
||||
new[] { replacement.Name, (replacement.SwappableItem.GetPrice(Campaign?.Map?.CurrentLocation) * linkedItems.Count).ToString() });
|
||||
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), promptBody, () =>
|
||||
{
|
||||
if (GameMain.NetworkMember != null)
|
||||
@@ -966,6 +986,7 @@ namespace Barotrauma
|
||||
|
||||
toggleButton.OnClicked = delegate
|
||||
{
|
||||
if (Campaign == null) { return false; }
|
||||
isOpen = !isOpen;
|
||||
toggleButton.Selected = !toggleButton.Selected;
|
||||
foreach (GUIFrame frame in frames)
|
||||
@@ -974,9 +995,10 @@ namespace Barotrauma
|
||||
}
|
||||
if (toggleButton.Selected)
|
||||
{
|
||||
var linkedItems = Campaign.UpgradeManager.GetLinkedItemsToSwap(item);
|
||||
foreach (var itemPreview in itemPreviews)
|
||||
{
|
||||
itemPreview.Value.OutlineColor = itemPreview.Value.Color = itemPreview.Key == item ? GUI.Style.Orange : previewWhite;
|
||||
itemPreview.Value.OutlineColor = itemPreview.Value.Color = linkedItems.Contains(itemPreview.Key) ? GUI.Style.Orange : previewWhite;
|
||||
}
|
||||
foreach (GUIComponent otherComponent in toggleButton.Parent.Children)
|
||||
{
|
||||
@@ -1145,9 +1167,9 @@ namespace Barotrauma
|
||||
private void CreateItemTooltip(MapEntity entity)
|
||||
{
|
||||
int slotIndex = -1;
|
||||
if (currentStoreLayout?.SelectedData is CategoryData categoryData)
|
||||
if (entity is Item swappableItem && swappableItem.Prefab.SwappableItem != null)
|
||||
{
|
||||
var entitiesOnSub = Submarine.MainSub.GetItems(true).Where(i => i.Prefab.SwappableItem != null && Submarine.MainSub.IsEntityFoundOnThisSub(i, true) && categoryData.Category.ItemTags.Any(t => i.HasTag(t))).ToList();
|
||||
var entitiesOnSub = Submarine.MainSub.GetItems(true).Where(i => i.Prefab.SwappableItem != null && Submarine.MainSub.IsEntityFoundOnThisSub(i, true) && i.Prefab.SwappableItem.SwapIdentifier == swappableItem.Prefab.SwappableItem?.SwapIdentifier).ToList();
|
||||
slotIndex = entitiesOnSub.IndexOf(entity) + 1;
|
||||
}
|
||||
|
||||
@@ -1231,6 +1253,8 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateSubmarinePreview(float deltaTime, GUICustomComponent parent)
|
||||
{
|
||||
if (Campaign == null) { return; }
|
||||
|
||||
if (!parent.Children.Any() || Submarine.MainSub != null && Submarine.MainSub != drawnSubmarine || GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y)
|
||||
{
|
||||
GameMain.GameSession?.SubmarineInfo?.CheckSubsLeftBehind();
|
||||
@@ -1279,7 +1303,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (selectedUpgradeCategoryLayout != null)
|
||||
{
|
||||
if (selectedUpgradeCategoryLayout.FindChild(c => c.UserData as Item == HoveredItem, recursive: true) is GUIButton itemElement)
|
||||
var linkedItems = HoveredItem is Item ? Campaign.UpgradeManager.GetLinkedItemsToSwap((Item)HoveredItem) : new List<Item>();
|
||||
if (selectedUpgradeCategoryLayout.FindChild(c => c.UserData as Item == HoveredItem || linkedItems.Contains(c.UserData as Item), recursive: true) is GUIButton itemElement)
|
||||
{
|
||||
if (!itemElement.Selected) { itemElement.OnClicked(itemElement, itemElement.UserData); }
|
||||
(itemElement.Parent?.Parent?.Parent as GUIListBox)?.ScrollToElement(itemElement);
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace Barotrauma
|
||||
if (IsMouseOver || (!RequireMouseOn && selectedWidgets.Contains(this) && PlayerInput.PrimaryMouseButtonHeld()))
|
||||
{
|
||||
Hovered?.Invoke();
|
||||
System.Diagnostics.Debug.WriteLine("hovered");
|
||||
if (RequireMouseOn || PlayerInput.PrimaryMouseButtonDown())
|
||||
{
|
||||
if ((multiselect && !selectedWidgets.Contains(this)) || selectedWidgets.None())
|
||||
@@ -126,6 +127,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (selectedWidgets.Contains(this))
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("selectedWidgets.Contains(this) -> remove");
|
||||
selectedWidgets.Remove(this);
|
||||
Deselected?.Invoke();
|
||||
}
|
||||
|
||||
@@ -140,8 +140,7 @@ namespace Barotrauma
|
||||
msg,
|
||||
((msgCommand == "r" || msgCommand == "radio") && ChatMessage.CanUseRadio(Character.Controlled)) ? ChatMessageType.Radio : ChatMessageType.Default,
|
||||
Character.Controlled);
|
||||
var headset = GetHeadset(Character.Controlled, true);
|
||||
if (headset != null && headset.CanTransmit())
|
||||
if (ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent headset))
|
||||
{
|
||||
Signal s = new Signal(msg, sender: Character.Controlled, source: headset.Item);
|
||||
headset.TransmitSignal(s, sentFromChat: true);
|
||||
@@ -610,17 +609,6 @@ namespace Barotrauma
|
||||
ChatBox.AddMessage(message);
|
||||
}
|
||||
|
||||
private WifiComponent GetHeadset(Character character, bool requireEquipped)
|
||||
{
|
||||
if (character?.Inventory == null) { return null; }
|
||||
|
||||
var radioItem = character.Inventory.AllItems.FirstOrDefault(it => it.GetComponent<WifiComponent>() != null);
|
||||
if (radioItem == null) { return null; }
|
||||
if (requireEquipped && !character.HasEquippedItem(radioItem)) { return null; }
|
||||
|
||||
return radioItem.GetComponent<WifiComponent>();
|
||||
}
|
||||
|
||||
partial void CreateRandomConversation()
|
||||
{
|
||||
if (GameMain.Client != null)
|
||||
@@ -1429,7 +1417,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (closestNode != null && closestNode == selectedNode)
|
||||
if (closestNode != null && closestNode.CanBeFocused && closestNode == selectedNode)
|
||||
{
|
||||
timeSelected += deltaTime;
|
||||
if (timeSelected >= selectionTime)
|
||||
@@ -2485,6 +2473,7 @@ namespace Barotrauma
|
||||
foreach (Order p in Order.PrefabList)
|
||||
{
|
||||
targetComponent = null;
|
||||
if (p.UseController && itemContext.Components.None(c => c is Controller)) { continue; }
|
||||
if ((p.TargetItems.Length > 0 && (p.TargetItems.Contains(itemContext.Prefab.Identifier) || itemContext.HasTag(p.TargetItems))) ||
|
||||
p.TryGetTargetItemComponent(itemContext, out targetComponent))
|
||||
{
|
||||
@@ -3444,10 +3433,8 @@ namespace Barotrauma
|
||||
bool canIssueOrders = false;
|
||||
if (Character.Controlled?.CurrentHull?.Submarine != null && Character.Controlled.SpeechImpediment < 100.0f)
|
||||
{
|
||||
WifiComponent radio = GetHeadset(Character.Controlled, true);
|
||||
canIssueOrders =
|
||||
radio != null &&
|
||||
radio.CanTransmit() &&
|
||||
ChatMessage.CanUseRadio(Character.Controlled) &&
|
||||
Character.Controlled?.CurrentHull?.Submarine?.TeamID == Character.Controlled.TeamID &&
|
||||
!Character.Controlled.CurrentHull.Submarine.Info.IsWreck;
|
||||
}
|
||||
|
||||
@@ -224,12 +224,7 @@ namespace Barotrauma
|
||||
{
|
||||
endRoundButton.ToolTip = buttonText;
|
||||
}
|
||||
if (Character.Controlled?.ViewTarget is Item item)
|
||||
{
|
||||
Turret turret = item.GetComponent<Turret>();
|
||||
endRoundButton.RectTransform.ScreenSpaceOffset = turret == null ? Point.Zero : new Point(0, (int)(turret.UIElementHeight * 1.25f));
|
||||
}
|
||||
else if (Character.Controlled?.CharacterHealth?.SuicideButton?.Visible ?? false)
|
||||
if (Character.Controlled?.CharacterHealth?.SuicideButton?.Visible ?? false)
|
||||
{
|
||||
endRoundButton.RectTransform.ScreenSpaceOffset = new Point(0, Character.Controlled.CharacterHealth.SuicideButton.Rect.Height);
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ namespace Barotrauma
|
||||
if (Vector2.DistanceSquared(Character.Controlled.WorldPosition, gap.ConnectedDoor.Item.WorldPosition) > 400 * 400) { continue; }
|
||||
if (!gap.IsRoomToRoom)
|
||||
{
|
||||
if (!(Character.Controlled.GetEquippedItem("deepdiving") is Item)) { continue; }
|
||||
if (!(Character.Controlled.GetEquippedItem("deepdiving", InvSlotType.OuterClothes) is Item)) { continue; }
|
||||
if (Character.Controlled.IsProtectedFromPressure()) { continue; }
|
||||
if (DisplayHint("divingsuitwarning", extendTextTag: false)) { return; }
|
||||
continue;
|
||||
|
||||
@@ -167,6 +167,13 @@ namespace Barotrauma.Items.Components
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(0, false)]
|
||||
public int HudLayer
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private bool useAlternativeLayout;
|
||||
public bool UseAlternativeLayout
|
||||
{
|
||||
@@ -443,6 +450,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }
|
||||
|
||||
public virtual void UpdateEditing(float deltaTime) { }
|
||||
|
||||
public virtual void CreateEditingHUD(SerializableEntityEditor editor)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -44,20 +44,6 @@ namespace Barotrauma.Items.Components
|
||||
private set;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Editable]
|
||||
#endif
|
||||
[Serialize("0.0,0.0", false, description: "The position where the contained items get drawn at (offset from the upper left corner of the sprite in pixels).")]
|
||||
public Vector2 ItemPos { get; set; }
|
||||
|
||||
#if DEBUG
|
||||
[Editable]
|
||||
#endif
|
||||
[Serialize("0.0,0.0", false, description: "The interval at which the contained items are spaced apart from each other (in pixels).")]
|
||||
public Vector2 ItemInterval { get; set; }
|
||||
[Serialize(100, false, description: "How many items are placed in a row before starting a new row.")]
|
||||
public int ItemsPerRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.
|
||||
/// </summary>
|
||||
@@ -291,7 +277,6 @@ namespace Barotrauma.Items.Components
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
|
||||
transformedItemPos += item.DrawPosition;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float[] charWidths;
|
||||
|
||||
private float prevScale;
|
||||
private Rectangle prevRect;
|
||||
private StringBuilder sb;
|
||||
|
||||
private Vector4 padding;
|
||||
|
||||
[Serialize("0,0,0,0", true, description: "The amount of padding around the text in pixels (left,top,right,bottom).")]
|
||||
@@ -49,7 +53,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
text = value;
|
||||
SetDisplayText(value);
|
||||
SetDisplayText(value);
|
||||
UpdateScrollingText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,9 +210,16 @@ namespace Barotrauma.Items.Components
|
||||
if (!needsScrolling) { return; }
|
||||
|
||||
scrollAmount -= deltaTime * ScrollSpeed;
|
||||
UpdateScrollingText();
|
||||
}
|
||||
|
||||
private void UpdateScrollingText()
|
||||
{
|
||||
if (!scrollable || !needsScrolling) { return; }
|
||||
|
||||
float currLength = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb ??= new StringBuilder();
|
||||
sb.Clear();
|
||||
float textAreaWidth = textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z;
|
||||
for (int i = scrollIndex; i < scrollingText.Length; i++)
|
||||
{
|
||||
@@ -246,10 +258,7 @@ namespace Barotrauma.Items.Components
|
||||
prevScale = item.Scale;
|
||||
prevRect = item.Rect;
|
||||
}
|
||||
|
||||
private float prevScale;
|
||||
private Rectangle prevRect;
|
||||
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
if (editing)
|
||||
@@ -267,15 +276,6 @@ namespace Barotrauma.Items.Components
|
||||
item.DrawPosition.X - item.Rect.Width / 2.0f,
|
||||
-(item.DrawPosition.Y + item.Rect.Height / 2.0f));
|
||||
|
||||
Rectangle worldRect = item.WorldRect;
|
||||
if (worldRect.X > Screen.Selected.Cam.WorldView.Right ||
|
||||
worldRect.Right < Screen.Selected.Cam.WorldView.X ||
|
||||
worldRect.Y < Screen.Selected.Cam.WorldView.Y - Screen.Selected.Cam.WorldView.Height ||
|
||||
worldRect.Y - worldRect.Height > Screen.Selected.Cam.WorldView.Y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
textBlock.TextDepth = item.SpriteDepth - 0.0001f;
|
||||
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + (editing ? Vector2.Zero : new Vector2(scrollAmount + scrollPadding, 0.0f));
|
||||
textBlock.DrawManually(spriteBatch);
|
||||
|
||||
@@ -561,7 +561,8 @@ namespace Barotrauma.Items.Components
|
||||
private bool StartButtonClicked(GUIButton button, object obj)
|
||||
{
|
||||
if (selectedItem == null) { return false; }
|
||||
if (fabricatedItem == null && !outputContainer.Inventory.CanBePut(selectedItem.TargetItem))
|
||||
if (fabricatedItem == null &&
|
||||
!outputContainer.Inventory.CanBePut(selectedItem.TargetItem, selectedItem.OutCondition))
|
||||
{
|
||||
outputSlot.Flash(GUI.Style.Red);
|
||||
return false;
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
|
||||
{
|
||||
if (DraggingConnected?.Item.Removed ?? false)
|
||||
{
|
||||
DraggingConnected = null;
|
||||
}
|
||||
Rectangle panelRect = panel.GuiFrame.Rect;
|
||||
int x = panelRect.X, y = panelRect.Y;
|
||||
int width = panelRect.Width, height = panelRect.Height;
|
||||
|
||||
@@ -304,6 +304,21 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateEditing(float deltaTime)
|
||||
{
|
||||
if (Screen.Selected == GameMain.SubEditorScreen && item.IsSelected)
|
||||
{
|
||||
if (widgets.ContainsKey("maxrotation"))
|
||||
{
|
||||
widgets["maxrotation"].Update(deltaTime);
|
||||
}
|
||||
if (widgets.ContainsKey("minrotation"))
|
||||
{
|
||||
widgets["minrotation"].Update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
if (crosshairSprite != null)
|
||||
@@ -469,7 +484,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
widget.tooltip = "Min: " + (int)MathHelper.ToDegrees(minRotation);
|
||||
widget.DrawPos = GetDrawPos() + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * coneRadius / Screen.Selected.Cam.Zoom * GUI.Scale;
|
||||
widget.Update(deltaTime);
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -1104,6 +1104,8 @@ namespace Barotrauma
|
||||
|
||||
public static void UpdateDragging()
|
||||
{
|
||||
DraggingItems.RemoveAll(it => !Character.Controlled.CanInteractWith(it));
|
||||
|
||||
if (DraggingItems.Any() && PlayerInput.PrimaryMouseButtonReleased())
|
||||
{
|
||||
Character.Controlled.ClearInputs();
|
||||
|
||||
@@ -22,6 +22,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<ItemComponent> activeHUDs = new List<ItemComponent>();
|
||||
|
||||
private readonly List<SerializableEntityEditor> activeEditors = new List<SerializableEntityEditor>();
|
||||
|
||||
public GUIComponentStyle IconStyle { get; private set; } = null;
|
||||
partial void AssignCampaignInteractionTypeProjSpecific(CampaignMode.InteractionType interactionType)
|
||||
{
|
||||
@@ -40,7 +42,6 @@ namespace Barotrauma
|
||||
public float LastImpactSoundTime;
|
||||
public const float ImpactSoundInterval = 0.2f;
|
||||
|
||||
private bool editingHUDRefreshPending;
|
||||
private float editingHUDRefreshTimer;
|
||||
|
||||
private ContainedItemSprite activeContainedSprite;
|
||||
@@ -581,14 +582,18 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
public override void UpdateEditing(Camera cam, float deltaTime)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData as Item != this ||
|
||||
(editingHUDRefreshPending && editingHUDRefreshTimer <= 0.0f))
|
||||
if (editingHUD == null || editingHUD.UserData as Item != this)
|
||||
{
|
||||
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
|
||||
editingHUDRefreshTimer = 1.0f;
|
||||
}
|
||||
if (editingHUDRefreshTimer <= 0.0f)
|
||||
{
|
||||
activeEditors.ForEach(e => e?.RefreshValues());
|
||||
editingHUDRefreshTimer = 1.0f;
|
||||
}
|
||||
|
||||
if (Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
|
||||
@@ -606,6 +611,11 @@ namespace Barotrauma
|
||||
|
||||
if (Character.Controlled == null) { activeHUDs.Clear(); }
|
||||
|
||||
foreach (ItemComponent ic in components)
|
||||
{
|
||||
ic.UpdateEditing(deltaTime);
|
||||
}
|
||||
|
||||
if (!Linkable) { return; }
|
||||
|
||||
if (!PlayerInput.KeyDown(Keys.Space)) { return; }
|
||||
@@ -632,7 +642,7 @@ namespace Barotrauma
|
||||
|
||||
public GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
editingHUDRefreshPending = false;
|
||||
activeEditors.Clear();
|
||||
|
||||
int heightScaled = (int)(20 * GUI.Scale);
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||
@@ -643,6 +653,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUI.LargeFont) { UserData = this };
|
||||
activeEditors.Add(itemEditor);
|
||||
itemEditor.Children.First().Color = Color.Black * 0.7f;
|
||||
if (!inGame)
|
||||
{
|
||||
@@ -782,6 +793,7 @@ namespace Barotrauma
|
||||
|
||||
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame, titleFont: GUI.SubHeadingFont) { UserData = ic };
|
||||
componentEditor.Children.First().Color = Color.Black * 0.7f;
|
||||
activeEditors.Add(componentEditor);
|
||||
|
||||
if (inGame)
|
||||
{
|
||||
@@ -976,7 +988,7 @@ namespace Barotrauma
|
||||
Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
GUIComponent prevEditingHUD = editingHUD;
|
||||
UpdateEditing(cam);
|
||||
UpdateEditing(cam, deltaTime);
|
||||
editingHUDCreated = editingHUD != null && editingHUD != prevEditingHUD;
|
||||
}
|
||||
|
||||
@@ -996,7 +1008,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (prefab.IsLinkAllowed(entity.prefab) && entity is Item i)
|
||||
{
|
||||
if (!i.DisplaySideBySideWhenLinked) continue;
|
||||
if (!i.DisplaySideBySideWhenLinked) { continue; }
|
||||
activeComponents.AddRange(i.components);
|
||||
}
|
||||
}
|
||||
@@ -1030,6 +1042,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
activeHUDs.Sort((h1, h2) => { return h2.HudLayer.CompareTo(h1.HudLayer); });
|
||||
|
||||
//active HUDs have changed, need to reposition
|
||||
if (!prevActiveHUDs.SequenceEqual(activeHUDs) || editingHUDCreated)
|
||||
{
|
||||
@@ -1132,8 +1146,6 @@ namespace Barotrauma
|
||||
}
|
||||
texts.Add(new ColoredText(nameText, GUI.Style.TextColor, false, false));
|
||||
|
||||
bool noComponentText = true;
|
||||
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||
{
|
||||
texts.Add(new ColoredText(TextManager.GetWithVariable($"CampaignInteraction.{CampaignInteractionType}", "[key]", GameMain.Config.KeyBindText(InputType.Use)), Color.Cyan, false, false));
|
||||
@@ -1159,7 +1171,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
texts.Add(new ColoredText(ic.DisplayMsg, color, false, false));
|
||||
noComponentText = false;
|
||||
}
|
||||
}
|
||||
if (PlayerInput.IsShiftDown() && CrewManager.DoesItemHaveContextualOrders(this))
|
||||
@@ -1295,7 +1306,6 @@ namespace Barotrauma
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
ReadPropertyChange(msg, false);
|
||||
editingHUDRefreshPending = true;
|
||||
break;
|
||||
case NetEntityEvent.Type.Upgrade:
|
||||
string identifier = msg.ReadString();
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Barotrauma
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
public override void UpdateEditing(Camera cam, float deltaTime)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData as Hull != this)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,14 @@ namespace Barotrauma
|
||||
|
||||
public LevelWallVertexBuffer(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
|
||||
{
|
||||
if (wallVertices.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Failed to instantiate a LevelWallVertexBuffer (no wall vertices).");
|
||||
}
|
||||
if (wallVertices.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Failed to instantiate a LevelWallVertexBuffer (no wall edge vertices).");
|
||||
}
|
||||
this.wallVertices = LevelRenderer.GetColoredVertices(wallVertices, color);
|
||||
WallBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, wallVertices.Length, BufferUsage.WriteOnly);
|
||||
WallBuffer.SetData(this.wallVertices);
|
||||
|
||||
@@ -617,14 +617,10 @@ namespace Barotrauma.Lights
|
||||
|
||||
private List<Vector2> FindRaycastHits()
|
||||
{
|
||||
if (!CastShadows)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (Range < 1.0f || Color.A < 1) { return null; }
|
||||
if (!CastShadows || Range < 1.0f || Color.A < 1) { return null; }
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
|
||||
|
||||
var hulls = new List<ConvexHull>();
|
||||
foreach (ConvexHullList chList in hullsInRange)
|
||||
@@ -826,13 +822,13 @@ namespace Barotrauma.Lights
|
||||
Vector2 dirNormal = new Vector2(-dir.Y, dir.X) * 3;
|
||||
|
||||
//do two slightly offset raycasts to hit the segment itself and whatever's behind it
|
||||
Pair<int,Vector2> intersection1 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 - dirNormal, visibleSegments);
|
||||
Pair<int,Vector2> intersection2 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 + dirNormal, visibleSegments);
|
||||
var intersection1 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 - dirNormal, visibleSegments);
|
||||
var intersection2 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 + dirNormal, visibleSegments);
|
||||
|
||||
if (intersection1.First < 0) return null;
|
||||
if (intersection2.First < 0) return null;
|
||||
Segment seg1 = visibleSegments[intersection1.First];
|
||||
Segment seg2 = visibleSegments[intersection2.First];
|
||||
if (intersection1.index < 0) return null;
|
||||
if (intersection2.index < 0) return null;
|
||||
Segment seg1 = visibleSegments[intersection1.index];
|
||||
Segment seg2 = visibleSegments[intersection2.index];
|
||||
|
||||
bool isPoint1 = MathUtils.LineToPointDistanceSquared(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
bool isPoint2 = MathUtils.LineToPointDistanceSquared(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
@@ -849,12 +845,12 @@ namespace Barotrauma.Lights
|
||||
hullList.IsHidden.Remove(seg2.ConvexHull);
|
||||
}
|
||||
}
|
||||
else if (intersection1.First != intersection2.First)
|
||||
else if (intersection1.index != intersection2.index)
|
||||
{
|
||||
//the raycasts landed on different segments
|
||||
//we definitely want to generate new geometry here
|
||||
output.Add(isPoint1 ? p.WorldPos : intersection1.Second);
|
||||
output.Add(isPoint2 ? p.WorldPos : intersection2.Second);
|
||||
output.Add(isPoint1 ? p.WorldPos : intersection1.pos);
|
||||
output.Add(isPoint2 ? p.WorldPos : intersection2.pos);
|
||||
|
||||
foreach (ConvexHullList hullList in hullsInRange)
|
||||
{
|
||||
@@ -884,7 +880,7 @@ namespace Barotrauma.Lights
|
||||
return output;
|
||||
}
|
||||
|
||||
private Pair<int, Vector2> RayCast(Vector2 rayStart, Vector2 rayEnd, List<Segment> segments)
|
||||
private (int index, Vector2 pos) RayCast(Vector2 rayStart, Vector2 rayEnd, List<Segment> segments)
|
||||
{
|
||||
Vector2? closestIntersection = null;
|
||||
int segment = -1;
|
||||
@@ -943,8 +939,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
Pair<int, Vector2> retVal = new Pair<int, Vector2>(segment, closestIntersection == null ? rayEnd : (Vector2)closestIntersection);
|
||||
return retVal;
|
||||
return (segment, closestIntersection == null ? rayEnd : (Vector2)closestIntersection);
|
||||
}
|
||||
|
||||
|
||||
@@ -1281,11 +1276,6 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (Range < 1.0f || Color.A < 1 || CurrentBrightness <= 0.0f) { return; }
|
||||
|
||||
if (CastShadows)
|
||||
{
|
||||
CheckHullsInRange();
|
||||
}
|
||||
|
||||
//if the light doesn't cast shadows, we can simply render the texture without having to calculate the light volume
|
||||
if (!CastShadows)
|
||||
{
|
||||
@@ -1298,16 +1288,27 @@ namespace Barotrauma.Lights
|
||||
float scale = Range / (currentTexture.Width / 2.0f);
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
spriteBatch.Draw(currentTexture, drawPos, null, Color.Multiply(CurrentBrightness), -rotation, center, scale, SpriteEffects.None, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
CheckHullsInRange();
|
||||
|
||||
if (NeedsRecalculation)
|
||||
{
|
||||
var verts = FindRaycastHits();
|
||||
if (verts == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Failed to generate vertices for a light source. Range: {Range}, color: {Color}, brightness: {CurrentBrightness}, parent: {ParentBody?.UserData ?? "Unknown"}");
|
||||
#endif
|
||||
Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateLightVertices(verts);
|
||||
|
||||
lastRecalculationTime = (float)Timing.TotalTime;
|
||||
|
||||
@@ -55,23 +55,23 @@ namespace Barotrauma
|
||||
GUI.DrawLine(spriteBatch, pos + Vector2.UnitX * 50.0f, pos - Vector2.UnitX * 50.0f, color * alpha, 0.0f, 5);
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
public override void UpdateEditing(Camera cam, float deltaTime)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData as LinkedSubmarine != this)
|
||||
{
|
||||
editingHUD = CreateEditingHUD();
|
||||
}
|
||||
|
||||
editingHUD.UpdateManually((float)Timing.Step);
|
||||
editingHUD.UpdateManually(deltaTime);
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonClicked() || !PlayerInput.KeyDown(Keys.Space)) return;
|
||||
if (!PlayerInput.PrimaryMouseButtonClicked() || !PlayerInput.KeyDown(Keys.Space)) { return; }
|
||||
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted || !(entity is Item) || !entity.IsMouseOn(position)) continue;
|
||||
if (((Item)entity).GetComponent<DockingPort>() == null) continue;
|
||||
if (entity == this || !entity.IsHighlighted || !(entity is Item) || !entity.IsMouseOn(position)) { continue; }
|
||||
if (((Item)entity).GetComponent<DockingPort>() == null) { continue; }
|
||||
if (linkedTo.Contains(entity))
|
||||
{
|
||||
linkedTo.Remove(entity);
|
||||
|
||||
@@ -838,9 +838,9 @@ namespace Barotrauma
|
||||
|
||||
public static List<MapEntity> FilteredSelectedList { get; private set; } = new List<MapEntity>();
|
||||
|
||||
public static void UpdateEditor(Camera cam)
|
||||
public static void UpdateEditor(Camera cam, float deltaTime)
|
||||
{
|
||||
if (highlightedListBox != null) highlightedListBox.UpdateManually((float)Timing.Step);
|
||||
if (highlightedListBox != null) { highlightedListBox.UpdateManually(deltaTime); }
|
||||
|
||||
if (editingHUD != null)
|
||||
{
|
||||
@@ -865,7 +865,7 @@ namespace Barotrauma
|
||||
var first = FilteredSelectedList.FirstOrDefault();
|
||||
if (first != null)
|
||||
{
|
||||
first.UpdateEditing(cam);
|
||||
first.UpdateEditing(cam, deltaTime);
|
||||
if (first.ResizeHorizontal || first.ResizeVertical)
|
||||
{
|
||||
first.UpdateResizing(cam);
|
||||
@@ -1017,7 +1017,7 @@ namespace Barotrauma
|
||||
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public virtual void UpdateEditing(Camera cam) { }
|
||||
public virtual void UpdateEditing(Camera cam, float deltaTime) { }
|
||||
|
||||
protected static void PositionEditingHUD()
|
||||
{
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma
|
||||
convexHulls.Add(h);
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
public override void UpdateEditing(Camera cam, float deltaTime)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData as Structure != this)
|
||||
{
|
||||
|
||||
@@ -53,8 +53,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string,HullCollection> hullCollections;
|
||||
private List<Door> doors;
|
||||
private readonly Dictionary<string, HullCollection> hullCollections;
|
||||
private readonly List<Door> doors;
|
||||
|
||||
|
||||
private static SubmarinePreview instance = null;
|
||||
@@ -104,7 +104,7 @@ namespace Barotrauma
|
||||
(spriteBatch, component) => {
|
||||
camera.UpdateTransform(interpolate: true, updateListener: false);
|
||||
Rectangle drawRect = new Rectangle(component.Rect.X + 1, component.Rect.Y + 1, component.Rect.Width - 2, component.Rect.Height - 2);
|
||||
RenderSubmarine(spriteBatch, drawRect);
|
||||
RenderSubmarine(spriteBatch, drawRect, component);
|
||||
},
|
||||
(deltaTime, component) => {
|
||||
bool isMouseOnComponent = GUI.MouseOn == component;
|
||||
@@ -121,6 +121,10 @@ namespace Barotrauma
|
||||
{
|
||||
specsContainer.Visible = GUI.IsMouseOn(titleText);
|
||||
}
|
||||
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
});
|
||||
|
||||
var topContainer = new GUIFrame(new RectTransform(new Vector2(1f, 0.07f), innerPadded.RectTransform, Anchor.TopLeft), style: null)
|
||||
@@ -225,6 +229,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (var subElement in submarineInfo.SubmarineElement.Elements())
|
||||
{
|
||||
if (subElement.GetAttributeBool("hiddeningame", false)) { continue; }
|
||||
switch (subElement.Name.LocalName.ToLowerInvariant())
|
||||
{
|
||||
case "item":
|
||||
@@ -240,8 +245,7 @@ namespace Barotrauma
|
||||
string identifier = subElement.GetAttributeString("roomname", "").ToLowerInvariant();
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
HullCollection hullCollection = null;
|
||||
if (!hullCollections.TryGetValue(identifier, out hullCollection))
|
||||
if (!hullCollections.TryGetValue(identifier, out HullCollection hullCollection))
|
||||
{
|
||||
hullCollection = new HullCollection(identifier);
|
||||
hullCollections.Add(identifier, hullCollection);
|
||||
@@ -476,12 +480,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
var transformedBarrelPos = MathUtils.RotatePointAroundTarget(
|
||||
subElement.GetAttributeVector2("barrelpos", Vector2.Zero) * scale,
|
||||
new Vector2(rect.Width / 2, rect.Height / 2),
|
||||
Vector2 barrelPos = subElement.GetAttributeVector2("barrelpos", Vector2.Zero);
|
||||
Vector2 relativeBarrelPos = barrelPos * prefab.Scale - new Vector2(rect.Width / 2, rect.Height / 2);
|
||||
var transformedBarrelPos = MathUtils.RotatePoint(
|
||||
relativeBarrelPos,
|
||||
MathHelper.ToRadians(rotation));
|
||||
|
||||
Vector2 drawPos = new Vector2(rect.X + transformedBarrelPos.X, rect.Y - transformedBarrelPos.Y);
|
||||
float relativeScale = scale / prefab.Scale;
|
||||
Vector2 drawPos = new Vector2(rect.X + rect.Width * relativeScale / 2 + transformedBarrelPos.X * relativeScale, rect.Y - rect.Height * relativeScale / 2 - transformedBarrelPos.Y * relativeScale);
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
railSprite?.Draw(spriteRecorder,
|
||||
@@ -491,7 +497,7 @@ namespace Barotrauma
|
||||
SpriteEffects.None, depth + (railSprite.Depth - prefab.sprite.Depth));
|
||||
|
||||
barrelSprite?.Draw(spriteRecorder,
|
||||
drawPos - new Vector2((float)Math.Cos(MathHelper.ToRadians(rotation)), (float)Math.Sin(MathHelper.ToRadians(rotation))) * scale,
|
||||
drawPos,
|
||||
color,
|
||||
rotation + MathHelper.PiOver2, scale,
|
||||
SpriteEffects.None, depth + (barrelSprite.Depth - prefab.sprite.Depth));
|
||||
@@ -564,7 +570,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderSubmarine(SpriteBatch spriteBatch, Rectangle scissorRectangle)
|
||||
private void RenderSubmarine(SpriteBatch spriteBatch, Rectangle scissorRectangle, GUIComponent component)
|
||||
{
|
||||
if (spriteRecorder == null) { return; }
|
||||
|
||||
@@ -605,11 +611,13 @@ namespace Barotrauma
|
||||
foreach (var hullCollection in hullCollections.Values)
|
||||
{
|
||||
bool mouseOver = false;
|
||||
|
||||
foreach (var rect in hullCollection.Rects)
|
||||
if (GUI.MouseOn == null || GUI.MouseOn == component)
|
||||
{
|
||||
mouseOver = rect.Contains(mousePos);
|
||||
if (mouseOver) { break; }
|
||||
foreach (var rect in hullCollection.Rects)
|
||||
{
|
||||
mouseOver = rect.Contains(mousePos);
|
||||
if (mouseOver) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var rect in hullCollection.Rects)
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
public override void UpdateEditing(Camera cam, float deltaTime)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData != this)
|
||||
{
|
||||
|
||||
@@ -318,9 +318,10 @@ namespace Barotrauma
|
||||
|
||||
if (MapGenerationParams.Instance.RadiationParams != null)
|
||||
{
|
||||
bool prevRadiationToggleEnabled = EnableRadiationToggle?.Selected ?? true;
|
||||
EnableRadiationToggle = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.3f), CampaignSettingsContent.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font)
|
||||
{
|
||||
Selected = true,
|
||||
Selected = prevRadiationToggleEnabled,
|
||||
ToolTip = TextManager.Get("campaignoption.enableradiation.tooltip")
|
||||
};
|
||||
}
|
||||
@@ -340,7 +341,9 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
MaxMissionCountText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), maxMissionCountContainer.RectTransform), CampaignSettings.DefaultMaxMissionCount.ToString(), textAlignment: Alignment.Center, style: "GUITextBox");
|
||||
|
||||
string prevMaxMissionCountText = MaxMissionCountText?.Text ?? CampaignSettings.DefaultMaxMissionCount.ToString();
|
||||
MaxMissionCountText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), maxMissionCountContainer.RectTransform), prevMaxMissionCountText, textAlignment: Alignment.Center, style: "GUITextBox");
|
||||
maxMissionCountButtons[1] = new GUIButton(new RectTransform(new Vector2(0.15f, 0.8f), maxMissionCountContainer.RectTransform), style: "GUIButtonToggleRight")
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
@@ -806,11 +809,12 @@ namespace Barotrauma
|
||||
UserData = "savefileframe"
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0.2f), saveFileFrame.RectTransform, Anchor.TopCenter)
|
||||
var titleText = new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.2f), saveFileFrame.RectTransform, Anchor.TopCenter)
|
||||
{
|
||||
RelativeOffset = new Vector2(0, 0.05f)
|
||||
},
|
||||
Path.GetFileNameWithoutExtension(fileName), font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||
titleText.Text = ToolBox.LimitString(titleText.Text, titleText.Font, titleText.Rect.Width);
|
||||
|
||||
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.5f), saveFileFrame.RectTransform, Anchor.Center)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Barotrauma
|
||||
|
||||
private GUIListBox missionList;
|
||||
private readonly List<GUITickBox> missionTickBoxes = new List<GUITickBox>();
|
||||
private readonly List<GUITextBlock> missionRewardTexts = new List<GUITextBlock>();
|
||||
|
||||
private bool hasMaxMissions;
|
||||
|
||||
@@ -368,6 +369,7 @@ namespace Barotrauma
|
||||
public void SelectLocation(Location location, LocationConnection connection)
|
||||
{
|
||||
missionTickBoxes.Clear();
|
||||
missionRewardTexts.Clear();
|
||||
locationInfoPanel.ClearChildren();
|
||||
//don't select the map panel if we're looking at some other tab
|
||||
if (selectedTab == CampaignMode.InteractionType.Map)
|
||||
@@ -524,6 +526,12 @@ namespace Barotrauma
|
||||
Campaign.Map.CurrentLocation.DeselectMission(mission);
|
||||
}
|
||||
|
||||
foreach (GUITextBlock rewardText in missionRewardTexts)
|
||||
{
|
||||
Mission otherMission = rewardText.UserData as Mission;
|
||||
rewardText.SetRichText(otherMission.GetMissionRewardText(Submarine.MainSub));
|
||||
}
|
||||
|
||||
UpdateMaxMissions(connection.OtherLocation(currentDisplayLocation));
|
||||
|
||||
if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending &&
|
||||
@@ -567,7 +575,11 @@ namespace Barotrauma
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform) { MinSize = new Point(0, GUI.IntScale(10)) }, style: null);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.GetMissionRewardText(Submarine.MainSub), wrap: true, parseRichText: true);
|
||||
var rewardText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.GetMissionRewardText(Submarine.MainSub), wrap: true, parseRichText: true)
|
||||
{
|
||||
UserData = mission
|
||||
};
|
||||
missionRewardTexts.Add(rewardText);
|
||||
|
||||
string reputationText = mission.GetReputationRewardText(mission.Locations[0]);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText, wrap: true, parseRichText: true);
|
||||
|
||||
@@ -119,6 +119,7 @@ namespace Barotrauma
|
||||
addValueDropdown.AddItem(nameof(LimbType), typeof(LimbType));
|
||||
addValueDropdown.AddItem(nameof(ReputationAction.ReputationType), typeof(ReputationAction.ReputationType));
|
||||
addValueDropdown.AddItem(nameof(SpawnAction.SpawnLocationType), typeof(SpawnAction.SpawnLocationType));
|
||||
addValueDropdown.AddItem(nameof(CharacterTeamType), typeof(CharacterTeamType));
|
||||
|
||||
loadButton.OnClicked += (button, o) => Load(loadDropdown.SelectedData as EventPrefab);
|
||||
addActionButton.OnClicked += (button, o) => AddAction(addActionDropdown.SelectedData as Type);
|
||||
|
||||
@@ -1089,6 +1089,7 @@ namespace Barotrauma
|
||||
itemContentPackage = ContentPackage.CreatePackage(sub.Name, Path.Combine(destinationFolder, SteamManager.MetadataFileName), corePackage: false);
|
||||
SteamManager.CreateWorkshopItemStaging(itemContentPackage, out itemEditor);
|
||||
|
||||
bool fileMoved = false;
|
||||
string submarineDir = Path.GetDirectoryName(sub.FilePath);
|
||||
if (submarineDir != Path.GetDirectoryName(destinationFolder))
|
||||
{
|
||||
@@ -1097,14 +1098,18 @@ namespace Barotrauma
|
||||
{
|
||||
File.Move(sub.FilePath, destinationPath);
|
||||
}
|
||||
fileMoved = true;
|
||||
sub.FilePath = destinationPath;
|
||||
}
|
||||
|
||||
itemContentPackage.AddFile(sub.FilePath, ContentType.Submarine);
|
||||
itemContentPackage.Name = sub.Name;
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
//ContentPackage.List.Add(itemContentPackage);
|
||||
//GameMain.Config.SelectContentPackage(itemContentPackage);
|
||||
|
||||
if (fileMoved)
|
||||
{
|
||||
GameMain.Config.EnableRegularPackage(itemContentPackage);
|
||||
}
|
||||
|
||||
itemEditor = itemEditor?.WithTitle(sub.Name).WithTag("Submarine").WithDescription(sub.Description);
|
||||
|
||||
|
||||
@@ -4696,7 +4696,7 @@ namespace Barotrauma
|
||||
CloseItem();
|
||||
}
|
||||
}
|
||||
MapEntity.UpdateEditor(cam);
|
||||
MapEntity.UpdateEditor(cam, (float)deltaTime);
|
||||
}
|
||||
|
||||
entityMenuOpenState = entityMenuOpen && !WiringMode ?
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace Barotrauma
|
||||
{
|
||||
class SerializableEntityEditor : GUIComponent
|
||||
{
|
||||
private int elementHeight;
|
||||
private GUILayoutGroup layoutGroup;
|
||||
private float inputFieldWidth = 0.5f;
|
||||
private float largeInputFieldWidth = 0.8f;
|
||||
private readonly int elementHeight;
|
||||
private readonly GUILayoutGroup layoutGroup;
|
||||
private readonly float inputFieldWidth = 0.5f;
|
||||
private readonly float largeInputFieldWidth = 0.8f;
|
||||
#if DEBUG
|
||||
public static List<string> MissingLocalizations = new List<string>();
|
||||
#endif
|
||||
@@ -23,6 +23,8 @@ namespace Barotrauma
|
||||
public static DateTime NextCommandPush;
|
||||
public static Tuple<SerializableProperty, PropertyCommand> CommandBuffer;
|
||||
|
||||
private Action refresh;
|
||||
|
||||
public int ContentHeight
|
||||
{
|
||||
get
|
||||
@@ -312,6 +314,11 @@ namespace Barotrauma
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
public void RefreshValues()
|
||||
{
|
||||
refresh?.Invoke();
|
||||
}
|
||||
|
||||
public void Recalculate() => RectTransform.Resize(new Point(RectTransform.NonScaledSize.X, ContentHeight));
|
||||
|
||||
public GUIComponent CreateNewField(SerializableProperty property, ISerializableEntity entity)
|
||||
@@ -459,6 +466,10 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
refresh += () =>
|
||||
{
|
||||
propertyTickBox.Selected = (bool)property.GetValue(entity);
|
||||
};
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { propertyTickBox }); }
|
||||
return propertyTickBox;
|
||||
}
|
||||
@@ -480,7 +491,7 @@ namespace Barotrauma
|
||||
ToolTip = toolTip,
|
||||
Font = GUI.SmallFont
|
||||
};
|
||||
field = numberInput as GUIComponent;
|
||||
field = numberInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -499,7 +510,11 @@ namespace Barotrauma
|
||||
TrySendNetworkUpdate(entity, property);
|
||||
}
|
||||
};
|
||||
field = numberInput as GUIComponent;
|
||||
refresh += () =>
|
||||
{
|
||||
if (!numberInput.TextBox.Selected) { numberInput.IntValue = (int)property.GetValue(entity); }
|
||||
};
|
||||
field = numberInput;
|
||||
}
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { field }); }
|
||||
return frame;
|
||||
@@ -538,6 +553,10 @@ namespace Barotrauma
|
||||
TrySendNetworkUpdate(entity, property);
|
||||
}
|
||||
};
|
||||
refresh += () =>
|
||||
{
|
||||
if (!numberInput.TextBox.Selected) { numberInput.FloatValue = (float)property.GetValue(entity); }
|
||||
};
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { numberInput }); }
|
||||
return frame;
|
||||
}
|
||||
@@ -567,6 +586,10 @@ namespace Barotrauma
|
||||
}
|
||||
return true;
|
||||
};
|
||||
refresh += () =>
|
||||
{
|
||||
if (!enumDropDown.Dropped) { enumDropDown.SelectItem(property.GetValue(entity)); }
|
||||
};
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, new GUIComponent[] { enumDropDown }); }
|
||||
return frame;
|
||||
}
|
||||
@@ -635,6 +658,10 @@ namespace Barotrauma
|
||||
|
||||
propertyBox.OnDeselected += (textBox, keys) => OnApply(textBox);
|
||||
propertyBox.OnEnterPressed += (box, text) => OnApply(box);
|
||||
refresh += () =>
|
||||
{
|
||||
if (!propertyBox.Selected) { propertyBox.Text = (string)property.GetValue(entity); }
|
||||
};
|
||||
|
||||
bool OnApply(GUITextBox textBox)
|
||||
{
|
||||
@@ -730,6 +757,15 @@ namespace Barotrauma
|
||||
};
|
||||
fields[i] = numberInput;
|
||||
}
|
||||
refresh += () =>
|
||||
{
|
||||
if (!fields.Any(f => ((GUINumberInput)f).TextBox.Selected))
|
||||
{
|
||||
Point value = (Point)property.GetValue(entity);
|
||||
((GUINumberInput)fields[0]).IntValue = value.X;
|
||||
((GUINumberInput)fields[1]).IntValue = value.Y;
|
||||
}
|
||||
};
|
||||
frame.RectTransform.MinSize = new Point(0, frame.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
|
||||
return frame;
|
||||
@@ -791,6 +827,15 @@ namespace Barotrauma
|
||||
};
|
||||
fields[i] = numberInput;
|
||||
}
|
||||
refresh += () =>
|
||||
{
|
||||
if (!fields.Any(f => ((GUINumberInput)f).TextBox.Selected))
|
||||
{
|
||||
Vector2 value = (Vector2)property.GetValue(entity);
|
||||
((GUINumberInput)fields[0]).FloatValue = value.X;
|
||||
((GUINumberInput)fields[1]).FloatValue = value.Y;
|
||||
}
|
||||
};
|
||||
frame.RectTransform.MinSize = new Point(0, frame.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
|
||||
return frame;
|
||||
@@ -857,6 +902,16 @@ namespace Barotrauma
|
||||
};
|
||||
fields[i] = numberInput;
|
||||
}
|
||||
refresh += () =>
|
||||
{
|
||||
if (!fields.Any(f => ((GUINumberInput)f).TextBox.Selected))
|
||||
{
|
||||
Vector3 value = (Vector3)property.GetValue(entity);
|
||||
((GUINumberInput)fields[0]).FloatValue = value.X;
|
||||
((GUINumberInput)fields[1]).FloatValue = value.Y;
|
||||
((GUINumberInput)fields[2]).FloatValue = value.Z;
|
||||
}
|
||||
};
|
||||
frame.RectTransform.MinSize = new Point(0, frame.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
|
||||
return frame;
|
||||
@@ -927,6 +982,17 @@ namespace Barotrauma
|
||||
};
|
||||
fields[i] = numberInput;
|
||||
}
|
||||
refresh += () =>
|
||||
{
|
||||
if (!fields.Any(f => ((GUINumberInput)f).TextBox.Selected))
|
||||
{
|
||||
Vector4 value = (Vector4)property.GetValue(entity);
|
||||
((GUINumberInput)fields[0]).FloatValue = value.X;
|
||||
((GUINumberInput)fields[1]).FloatValue = value.Y;
|
||||
((GUINumberInput)fields[2]).FloatValue = value.Z;
|
||||
((GUINumberInput)fields[3]).FloatValue = value.W;
|
||||
}
|
||||
};
|
||||
frame.RectTransform.MinSize = new Point(0, frame.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
|
||||
return frame;
|
||||
@@ -993,13 +1059,13 @@ namespace Barotrauma
|
||||
{
|
||||
Color newVal = (Color)property.GetValue(entity);
|
||||
if (comp == 0)
|
||||
newVal.R = (byte)(numInput.IntValue);
|
||||
newVal.R = (byte)numInput.IntValue;
|
||||
else if (comp == 1)
|
||||
newVal.G = (byte)(numInput.IntValue);
|
||||
newVal.G = (byte)numInput.IntValue;
|
||||
else if (comp == 2)
|
||||
newVal.B = (byte)(numInput.IntValue);
|
||||
newVal.B = (byte)numInput.IntValue;
|
||||
else
|
||||
newVal.A = (byte)(numInput.IntValue);
|
||||
newVal.A = (byte)numInput.IntValue;
|
||||
|
||||
if (SetPropertyValue(property, entity, newVal))
|
||||
{
|
||||
@@ -1010,6 +1076,17 @@ namespace Barotrauma
|
||||
colorBox.Color = colorBox.HoverColor = colorBox.PressedColor = colorBox.SelectedTextColor = (Color)property.GetValue(entity);
|
||||
fields[i] = numberInput;
|
||||
}
|
||||
refresh += () =>
|
||||
{
|
||||
if (!fields.Any(f => ((GUINumberInput)f).TextBox.Selected))
|
||||
{
|
||||
Color value = (Color)property.GetValue(entity);
|
||||
((GUINumberInput)fields[0]).IntValue = value.R;
|
||||
((GUINumberInput)fields[1]).IntValue = value.G;
|
||||
((GUINumberInput)fields[2]).IntValue = value.B;
|
||||
((GUINumberInput)fields[3]).IntValue = value.A;
|
||||
}
|
||||
};
|
||||
frame.RectTransform.MinSize = new Point(0, frame.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
|
||||
return frame;
|
||||
@@ -1072,6 +1149,17 @@ namespace Barotrauma
|
||||
};
|
||||
fields[i] = numberInput;
|
||||
}
|
||||
refresh += () =>
|
||||
{
|
||||
if (!fields.Any(f => ((GUINumberInput)f).TextBox.Selected))
|
||||
{
|
||||
Rectangle value = (Rectangle)property.GetValue(entity);
|
||||
((GUINumberInput)fields[0]).IntValue = value.X;
|
||||
((GUINumberInput)fields[1]).IntValue = value.Y;
|
||||
((GUINumberInput)fields[2]).IntValue = value.Width;
|
||||
((GUINumberInput)fields[3]).IntValue = value.Height;
|
||||
}
|
||||
};
|
||||
if (!Fields.ContainsKey(property.Name)) { Fields.Add(property.Name, fields); }
|
||||
return frame;
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
public class SoundBuffers : IDisposable
|
||||
{
|
||||
private static HashSet<uint> bufferPool = new HashSet<uint>();
|
||||
private static readonly HashSet<uint> bufferPool = new HashSet<uint>();
|
||||
#if OSX
|
||||
public const int MaxBuffers = 400; //TODO: check that this value works for macOS
|
||||
#else
|
||||
public const int MaxBuffers = 32000;
|
||||
#endif
|
||||
public static int BuffersGenerated { get; private set; } = 0;
|
||||
private Sound sound;
|
||||
private readonly Sound sound;
|
||||
|
||||
public uint AlBuffer { get; private set; } = 0;
|
||||
public uint AlMuffledBuffer { get; private set; } = 0;
|
||||
@@ -24,55 +24,73 @@ namespace Barotrauma.Sounds
|
||||
public SoundBuffers(Sound sound) { this.sound = sound; }
|
||||
public void Dispose()
|
||||
{
|
||||
if (AlBuffer != 0) { bufferPool.Add(AlBuffer); }
|
||||
if (AlMuffledBuffer != 0) { bufferPool.Add(AlMuffledBuffer); }
|
||||
if (AlBuffer != 0)
|
||||
{
|
||||
lock (bufferPool)
|
||||
{
|
||||
bufferPool.Add(AlBuffer);
|
||||
}
|
||||
}
|
||||
if (AlMuffledBuffer != 0)
|
||||
{
|
||||
lock (bufferPool)
|
||||
{
|
||||
bufferPool.Add(AlMuffledBuffer);
|
||||
}
|
||||
}
|
||||
AlBuffer = 0;
|
||||
AlMuffledBuffer = 0;
|
||||
}
|
||||
|
||||
public static void ClearPool()
|
||||
{
|
||||
bufferPool.ForEach(b => Al.DeleteBuffer(b));
|
||||
bufferPool.Clear();
|
||||
lock (bufferPool)
|
||||
{
|
||||
bufferPool.ForEach(b => Al.DeleteBuffer(b));
|
||||
bufferPool.Clear();
|
||||
}
|
||||
BuffersGenerated = 0;
|
||||
}
|
||||
|
||||
public bool RequestAlBuffers()
|
||||
{
|
||||
if (AlBuffer != 0) { return false; }
|
||||
int alError = 0;
|
||||
while (bufferPool.Count < 2 && BuffersGenerated < MaxBuffers)
|
||||
int alError;
|
||||
lock (bufferPool)
|
||||
{
|
||||
Al.GenBuffer(out uint newBuffer);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
while (bufferPool.Count < 2 && BuffersGenerated < MaxBuffers)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error when generating sound buffer: {Al.GetErrorString(alError)}. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
|
||||
BuffersGenerated = MaxBuffers;
|
||||
}
|
||||
else if (!Al.IsBuffer(newBuffer))
|
||||
{
|
||||
DebugConsole.AddWarning($"Error when generating sound buffer: result is not a valid buffer. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
|
||||
BuffersGenerated = MaxBuffers;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferPool.Add(newBuffer);
|
||||
BuffersGenerated++;
|
||||
if (BuffersGenerated >= MaxBuffers)
|
||||
Al.GenBuffer(out uint newBuffer);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.AddWarning($"{BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
|
||||
DebugConsole.AddWarning($"Error when generating sound buffer: {Al.GetErrorString(alError)}. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
|
||||
BuffersGenerated = MaxBuffers;
|
||||
}
|
||||
else if (!Al.IsBuffer(newBuffer))
|
||||
{
|
||||
DebugConsole.AddWarning($"Error when generating sound buffer: result is not a valid buffer. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
|
||||
BuffersGenerated = MaxBuffers;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferPool.Add(newBuffer);
|
||||
BuffersGenerated++;
|
||||
if (BuffersGenerated >= MaxBuffers)
|
||||
{
|
||||
DebugConsole.AddWarning($"{BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferPool.Count >= 2)
|
||||
{
|
||||
AlBuffer = bufferPool.First();
|
||||
bufferPool.Remove(AlBuffer);
|
||||
AlMuffledBuffer = bufferPool.First();
|
||||
bufferPool.Remove(AlMuffledBuffer);
|
||||
return true;
|
||||
if (bufferPool.Count >= 2)
|
||||
{
|
||||
AlBuffer = bufferPool.First();
|
||||
bufferPool.Remove(AlBuffer);
|
||||
AlMuffledBuffer = bufferPool.First();
|
||||
bufferPool.Remove(AlMuffledBuffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//can't generate any more OpenAL buffers! we'll have to steal a buffer from someone...
|
||||
@@ -112,7 +130,6 @@ namespace Barotrauma.Sounds
|
||||
throw new Exception(sound.Filename + " has an invalid muffled buffer!");
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,10 +167,10 @@ namespace Barotrauma.Sounds
|
||||
public CategoryModifier(int gainMultiplierIndex, float gain, bool muffle)
|
||||
{
|
||||
Muffle = muffle;
|
||||
GainMultipliers = new float[gainMultiplierIndex+1];
|
||||
for (int i=0;i<GainMultipliers.Length;i++)
|
||||
GainMultipliers = new float[gainMultiplierIndex + 1];
|
||||
for (int i = 0; i < GainMultipliers.Length; i++)
|
||||
{
|
||||
if (i==gainMultiplierIndex)
|
||||
if (i == gainMultiplierIndex)
|
||||
{
|
||||
GainMultipliers[i] = gain;
|
||||
}
|
||||
@@ -183,11 +183,11 @@ namespace Barotrauma.Sounds
|
||||
|
||||
public void SetGainMultiplier(int index, float gain)
|
||||
{
|
||||
if (GainMultipliers.Length < index+1)
|
||||
if (GainMultipliers.Length < index + 1)
|
||||
{
|
||||
int oldLength = GainMultipliers.Length;
|
||||
Array.Resize(ref GainMultipliers, index + 1);
|
||||
for (int i=oldLength;i<GainMultipliers.Length;i++)
|
||||
for (int i = oldLength; i < GainMultipliers.Length; i++)
|
||||
{
|
||||
GainMultipliers[i] = 1.0f;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Barotrauma
|
||||
{
|
||||
OverrideMusicType = null;
|
||||
|
||||
var soundFiles = GameMain.Instance.GetFilesOfType(ContentType.Sounds);
|
||||
var soundFiles = GameMain.Instance.GetFilesOfType(ContentType.Sounds).ToList();
|
||||
|
||||
List<XElement> soundElements = new List<XElement>();
|
||||
foreach (ContentFile soundFile in soundFiles)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.14.6.0</Version>
|
||||
<Version>0.1400.7.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.14.6.0</Version>
|
||||
<Version>0.1400.7.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
@@ -94,7 +94,7 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)'!='Debug'">
|
||||
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
|
||||
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" AdditionalProperties="Configuration=Release" />
|
||||
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
|
||||
@@ -104,6 +104,16 @@
|
||||
<ProjectReference Include="..\..\Libraries\SharpFont\Source\SharpFont\SharpFont.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
|
||||
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.MacOS.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\SharpFont\Source\SharpFont\SharpFont.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.MacOS.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.14.6.0</Version>
|
||||
<Version>0.1400.7.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.14.6.0</Version>
|
||||
<Version>0.1400.7.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.14.6.0</Version>
|
||||
<Version>0.1400.7.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,6 +6,11 @@ namespace Barotrauma
|
||||
{
|
||||
public bool HasSpawned;
|
||||
|
||||
public bool HasItemData
|
||||
{
|
||||
get { return itemData != null; }
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(Client client)
|
||||
{
|
||||
ClientEndPoint = client.Connection.EndPointString;
|
||||
|
||||
@@ -172,11 +172,25 @@ namespace Barotrauma
|
||||
//refresh the character data of clients who are still in the server
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath?.Type != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
//the client has opted to spawn this round with Reaper's Tax
|
||||
if (c.WaitForNextRoundRespawn.HasValue && !c.WaitForNextRoundRespawn.Value)
|
||||
{
|
||||
c.CharacterInfo.StartItemsGiven = false;
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
characterData.Add(new CharacterCampaignData(c, giveRespawnPenaltyAffliction: true));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c.Character?.Info == null) { continue; }
|
||||
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { continue; }
|
||||
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
c.CharacterInfo = c.Character.Info;
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
}
|
||||
|
||||
//refresh the character data of clients who aren't in the server anymore
|
||||
|
||||
@@ -70,18 +70,20 @@ namespace Barotrauma
|
||||
{
|
||||
Item droppedItem = item;
|
||||
Entity prevOwner = Owner;
|
||||
Inventory previousInventory = droppedItem.ParentInventory;
|
||||
droppedItem.Drop(null);
|
||||
droppedItem.PreviousParentInventory = previousInventory;
|
||||
|
||||
var previousInventory = prevOwner switch
|
||||
var previousCharacterInventory = prevOwner switch
|
||||
{
|
||||
Item itemInventory => (itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory),
|
||||
Item itemInventory => itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory,
|
||||
Character character => character.Inventory,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (previousInventory != null && previousInventory != c.Character?.Inventory)
|
||||
if (previousCharacterInventory != null && previousCharacterInventory != c.Character?.Inventory)
|
||||
{
|
||||
GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousInventory, c, droppedItem);
|
||||
GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousCharacterInventory, c, droppedItem);
|
||||
}
|
||||
|
||||
if (droppedItem.body != null && prevOwner != null)
|
||||
@@ -109,7 +111,8 @@ namespace Barotrauma
|
||||
var holdable = item.GetComponent<Holdable>();
|
||||
if (holdable != null && !holdable.CanBeDeattached()) { continue; }
|
||||
|
||||
if (!prevItems.Contains(item) && !item.CanClientAccess(c))
|
||||
if (!prevItems.Contains(item) && !item.CanClientAccess(c) &&
|
||||
(c.Character == null || item.PreviousParentInventory == null || !c.Character.CanAccessInventory(item.PreviousParentInventory)))
|
||||
{
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {(item.ParentInventory?.Owner.ToString() ?? "null")}). No access.", Color.Yellow);
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Barotrauma
|
||||
{
|
||||
private CoroutineHandle logPropertyChangeCoroutine;
|
||||
|
||||
public Inventory PreviousParentInventory;
|
||||
|
||||
public override Sprite Sprite
|
||||
{
|
||||
get { return prefab?.sprite; }
|
||||
|
||||
@@ -36,21 +36,21 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
msg.Write(Offset.X);
|
||||
msg.Write(Offset.Y);
|
||||
}
|
||||
|
||||
|
||||
public void ServerWriteBranchGrowth(IWriteMessage msg, BallastFloraBranch branch, int parentId = -1)
|
||||
{
|
||||
var (x, y) = branch.Position;
|
||||
msg.Write(parentId);
|
||||
msg.Write((int)branch.ID);
|
||||
msg.WriteRangedInteger((byte) branch.Type, 0b0000, 0b1111);
|
||||
msg.WriteRangedInteger((byte) branch.Sides, 0b0000, 0b1111);
|
||||
msg.WriteRangedInteger((byte)branch.Type, 0b0000, 0b1111);
|
||||
msg.WriteRangedInteger((byte)branch.Sides, 0b0000, 0b1111);
|
||||
msg.WriteRangedInteger(branch.FlowerConfig.Serialize(), 0, 0xFFF);
|
||||
msg.WriteRangedInteger(branch.LeafConfig.Serialize(), 0, 0xFFF);
|
||||
msg.Write((ushort) branch.MaxHealth);
|
||||
msg.Write((int) (x / VineTile.Size));
|
||||
msg.Write((int) (y / VineTile.Size));
|
||||
msg.Write((ushort)branch.MaxHealth);
|
||||
msg.Write((int)(x / VineTile.Size));
|
||||
msg.Write((int)(y / VineTile.Size));
|
||||
}
|
||||
|
||||
|
||||
public void ServerWriteBranchDamage(IWriteMessage msg, BallastFloraBranch branch, float damage)
|
||||
{
|
||||
msg.Write((int)branch.ID);
|
||||
|
||||
@@ -2342,7 +2342,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
characterData.SpawnInventoryItems(spawnedCharacter, spawnedCharacter.Inventory);
|
||||
if (!characterData.HasItemData && !characterData.CharacterInfo.StartItemsGiven)
|
||||
{
|
||||
//clients who've chosen to spawn with the respawn penalty can have CharacterData without inventory data
|
||||
spawnedCharacter.GiveJobItems(mainSubWaypoints[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
characterData.SpawnInventoryItems(spawnedCharacter, spawnedCharacter.Inventory);
|
||||
}
|
||||
characterData.ApplyHealthData(spawnedCharacter);
|
||||
characterData.ApplyOrderData(spawnedCharacter);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
@@ -3058,13 +3066,7 @@ namespace Barotrauma.Networking
|
||||
case ChatMessageType.Radio:
|
||||
case ChatMessageType.Order:
|
||||
if (senderCharacter == null) { return; }
|
||||
|
||||
//return if senderCharacter doesn't have a working radio
|
||||
var radio = senderCharacter.Inventory?.AllItems.FirstOrDefault(i => i.GetComponent<WifiComponent>() != null);
|
||||
if (radio == null || !senderCharacter.HasEquippedItem(radio)) { return; }
|
||||
|
||||
senderRadio = radio.GetComponent<WifiComponent>();
|
||||
if (!senderRadio.CanTransmit()) { return; }
|
||||
if (!ChatMessage.CanUseRadio(senderCharacter, out senderRadio)) { return; }
|
||||
break;
|
||||
case ChatMessageType.Dead:
|
||||
//character still alive and capable of speaking -> dead chat not allowed
|
||||
|
||||
@@ -411,11 +411,7 @@ namespace Barotrauma.Networking
|
||||
var characterData = campaign?.GetClientCharacterData(clients[i]);
|
||||
if (characterData != null && Level.Loaded?.Type != LevelData.LevelType.Outpost && characterData.HasSpawned)
|
||||
{
|
||||
var respawnPenaltyAffliction = AfflictionPrefab.List.FirstOrDefault(a => a.AfflictionType.Equals("respawnpenalty", StringComparison.OrdinalIgnoreCase));
|
||||
if (respawnPenaltyAffliction != null)
|
||||
{
|
||||
character.CharacterHealth.ApplyAffliction(targetLimb: null, respawnPenaltyAffliction.Instantiate(10.0f));
|
||||
}
|
||||
GiveRespawnPenaltyAffliction(character);
|
||||
}
|
||||
|
||||
if (characterData == null || characterData.HasSpawned)
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace Barotrauma
|
||||
List<Item> suitableItems = new List<Item>();
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.HiddenInGame || item.NonInteractable || item.NonPlayerTeamInteractable) { continue; }
|
||||
if (item.Submarine == null || traitors.All(traitor => item.Submarine.TeamID != traitor.Character.TeamID))
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.14.6.0</Version>
|
||||
<Version>0.1400.7.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -300,9 +300,9 @@ namespace Barotrauma
|
||||
if (containedItem == null) { continue; }
|
||||
if (predicate == null || predicate(containedItem))
|
||||
{
|
||||
if (character.Submarine != Submarine.MainSub && avoidDroppingInSea)
|
||||
if (avoidDroppingInSea && !character.IsInFriendlySub)
|
||||
{
|
||||
// If we are outside of main sub, try to put the item in the inventory instead dropping it in the sea.
|
||||
// If we are not inside a friendly sub (= same team), try to put the item in the inventory instead dropping it.
|
||||
if (character.Inventory.TryPutItem(containedItem, character, CharacterInventory.anySlot))
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -2595,7 +2595,7 @@ namespace Barotrauma
|
||||
{
|
||||
if ((SelectedAiTarget != null || wallTarget != null) && IsLatchedOnSub)
|
||||
{
|
||||
if (!(SelectedAiTarget.Entity is Structure wall))
|
||||
if (!(SelectedAiTarget?.Entity is Structure wall))
|
||||
{
|
||||
wall = wallTarget?.Structure;
|
||||
}
|
||||
|
||||
@@ -475,14 +475,16 @@ namespace Barotrauma
|
||||
bool needsGear = NeedsDivingGear(Character.CurrentHull, out _);
|
||||
if (!needsGear || oxygenLow)
|
||||
{
|
||||
bool shouldKeepTheGearOn =
|
||||
bool isCurrentObjectiveFindSafety = ObjectiveManager.IsCurrentObjective<AIObjectiveFindSafety>();
|
||||
bool shouldKeepTheGearOn =
|
||||
isCurrentObjectiveFindSafety ||
|
||||
Character.AnimController.InWater ||
|
||||
Character.AnimController.HeadInWater ||
|
||||
Character.CurrentHull == null ||
|
||||
(Character.Submarine?.TeamID != Character.TeamID && !Character.IsEscorted) || // these instances should maybe be combined to a method
|
||||
ObjectiveManager.IsCurrentObjective<AIObjectiveFindSafety>() ||
|
||||
Character.Submarine == null ||
|
||||
(Character.Submarine.TeamID != Character.TeamID && !Character.IsEscorted) ||
|
||||
ObjectiveManager.CurrentObjective.GetSubObjectivesRecursive(true).Any(o => o.KeepDivingGearOn);
|
||||
if (oxygenLow && Character.CurrentHull.Oxygen > 0)
|
||||
if (oxygenLow && Character.CurrentHull.Oxygen > 0 && (!isCurrentObjectiveFindSafety || Character.OxygenAvailable < 1))
|
||||
{
|
||||
shouldKeepTheGearOn = false;
|
||||
}
|
||||
@@ -1348,13 +1350,15 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Check whether the character has a diving suit in usable condition plus some oxygen.
|
||||
/// </summary>
|
||||
public static bool HasDivingSuit(Character character, float conditionPercentage = 0) => HasItem(character, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out _, AIObjectiveFindDivingGear.OXYGEN_SOURCE, conditionPercentage, requireEquipped: true,
|
||||
predicate: (Item item) => { return character.HasEquippedItem(item, InvSlotType.OuterClothes); });
|
||||
public static bool HasDivingSuit(Character character, float conditionPercentage = 0)
|
||||
=> HasItem(character, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out _, AIObjectiveFindDivingGear.OXYGEN_SOURCE, conditionPercentage, requireEquipped: true,
|
||||
predicate: (Item item) => character.HasEquippedItem(item, InvSlotType.OuterClothes));
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the character has a diving mask in usable condition plus some oxygen.
|
||||
/// </summary>
|
||||
public static bool HasDivingMask(Character character, float conditionPercentage = 0) => HasItem(character, AIObjectiveFindDivingGear.LIGHT_DIVING_GEAR, out _, AIObjectiveFindDivingGear.OXYGEN_SOURCE, conditionPercentage, requireEquipped: true);
|
||||
public static bool HasDivingMask(Character character, float conditionPercentage = 0)
|
||||
=> HasItem(character, AIObjectiveFindDivingGear.LIGHT_DIVING_GEAR, out _, AIObjectiveFindDivingGear.OXYGEN_SOURCE, conditionPercentage, requireEquipped: true);
|
||||
|
||||
private static List<Item> matchingItems = new List<Item>();
|
||||
|
||||
@@ -2048,7 +2052,7 @@ namespace Barotrauma
|
||||
{
|
||||
var repairItemsObjective = operatingAI.ObjectiveManager.GetObjective<AIObjectiveRepairItems>();
|
||||
if (repairItemsObjective == null) { continue; }
|
||||
if (repairItemsObjective.SubObjectives.None(o => o is AIObjectiveRepairItem repairObjective && repairObjective.Item == target))
|
||||
if (!(repairItemsObjective.SubObjectives.FirstOrDefault(o => o is AIObjectiveRepairItem) is AIObjectiveRepairItem activeObjective) || activeObjective.Item != target)
|
||||
{
|
||||
// Not targeting the same item.
|
||||
continue;
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ItemToContain.ParentInventory == character.Inventory && character.Submarine == Submarine.MainSub)
|
||||
if (ItemToContain.ParentInventory == character.Inventory && character.IsInFriendlySub)
|
||||
{
|
||||
ItemToContain.Drop(character);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Barotrauma
|
||||
if (HumanAIController.NeedsDivingGear(character.CurrentHull, out bool needsSuit) &&
|
||||
(needsSuit ?
|
||||
!HumanAIController.HasDivingSuit(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN) :
|
||||
!HumanAIController.HasDivingMask(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN)))
|
||||
!HumanAIController.HasDivingGear(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN)))
|
||||
{
|
||||
Priority = 100;
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace Barotrauma
|
||||
|
||||
void ReportWeldingFuelTankCount()
|
||||
{
|
||||
if (character.Submarine != Submarine.MainSub) { return; }
|
||||
int remainingOxygenTanks = Submarine.MainSub.GetItems(false).Count(i => i.HasTag("weldingfuel") && i.Condition > 1);
|
||||
if (remainingOxygenTanks == 0)
|
||||
{
|
||||
@@ -131,7 +132,7 @@ namespace Barotrauma
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
Vector2 toLeak = Leak.WorldPosition - character.WorldPosition;
|
||||
Vector2 toLeak = Leak.WorldPosition - character.AnimController.AimSourceWorldPos;
|
||||
// TODO: use the collider size/reach?
|
||||
if (!character.AnimController.InWater && Math.Abs(toLeak.X) < 100 && toLeak.Y < 0.0f && toLeak.Y > -150)
|
||||
{
|
||||
@@ -157,6 +158,7 @@ namespace Barotrauma
|
||||
{
|
||||
TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(Leak, character, objectiveManager)
|
||||
{
|
||||
UseDistanceRelativeToAimSourcePos = true,
|
||||
CloseEnough = reach,
|
||||
DialogueIdentifier = Leak.FlowTargetHull != null ? "dialogcannotreachleak" : null,
|
||||
TargetName = Leak.FlowTargetHull?.DisplayName,
|
||||
@@ -165,7 +167,7 @@ namespace Barotrauma
|
||||
onAbandon: () =>
|
||||
{
|
||||
if (CheckObjectiveSpecific()) { IsCompleted = true; }
|
||||
else if ((Leak.WorldPosition - character.WorldPosition).LengthSquared() > MathUtils.Pow(reach * 2, 2))
|
||||
else if ((Leak.WorldPosition - character.AnimController.AimSourceWorldPos).LengthSquared() > MathUtils.Pow(reach * 2, 2))
|
||||
{
|
||||
// Too far
|
||||
Abandon = true;
|
||||
|
||||
@@ -66,6 +66,11 @@ namespace Barotrauma
|
||||
|
||||
public bool AlwaysUseEuclideanDistance { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the distance to the destination is calculated from the character's AimSourcePos (= shoulder) instead of the collider's position
|
||||
/// </summary>
|
||||
public bool UseDistanceRelativeToAimSourcePos { get; set; } = false;
|
||||
|
||||
public override bool AbandonWhenCannotCompleteSubjectives => !repeat;
|
||||
|
||||
public override bool AllowOutsideSubmarine => AllowGoingOutside;
|
||||
@@ -589,7 +594,9 @@ namespace Barotrauma
|
||||
float xDiff = Math.Abs(Target.WorldPosition.X - character.WorldPosition.X);
|
||||
return xDiff <= CloseEnough;
|
||||
}
|
||||
return Vector2.DistanceSquared(Target.WorldPosition, character.WorldPosition) < CloseEnough * CloseEnough;
|
||||
|
||||
Vector2 sourcePos = UseDistanceRelativeToAimSourcePos ? character.AnimController.AimSourceWorldPos : character.WorldPosition;
|
||||
return Vector2.DistanceSquared(Target.WorldPosition, sourcePos) < CloseEnough * CloseEnough;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +215,9 @@ namespace Barotrauma
|
||||
var objective = new AIObjectiveGoTo(Item, character, objectiveManager)
|
||||
{
|
||||
// Don't stop in ladders, because we can't interact with other items while holding the ladders.
|
||||
endNodeFilter = node => node.Waypoint.Ladders == null
|
||||
endNodeFilter = node => node.Waypoint.Ladders == null,
|
||||
// Allow repairing hatches and airlock doors.
|
||||
AllowGoingOutside = HumanAIController.ObjectiveManager.IsCurrentOrder<AIObjectiveRepairItems>() && Item.GetComponent<Door>() != null
|
||||
};
|
||||
if (repairTool != null)
|
||||
{
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace Barotrauma
|
||||
public static bool ViableForRepair(Item item, Character character, HumanAIController humanAIController)
|
||||
{
|
||||
if (!IsValidTarget(item, character)) { return false; }
|
||||
if (item.CurrentHull == null) { return true; }
|
||||
if (item.CurrentHull.FireSources.Count > 0) { return false; }
|
||||
// Don't repair items in rooms that have enemies inside.
|
||||
if (Character.CharacterList.Any(c => c.CurrentHull == item.CurrentHull && !humanAIController.IsFriendly(c) && HumanAIController.IsActive(c))) { return false; }
|
||||
@@ -150,7 +151,6 @@ namespace Barotrauma
|
||||
if (item.IgnoreByAI(character)) { return false; }
|
||||
if (!item.IsInteractable(character)) { return false; }
|
||||
if (item.IsFullCondition) { return false; }
|
||||
if (item.CurrentHull == null) { return false; }
|
||||
if (item.Submarine == null || character.Submarine == null) { return false; }
|
||||
//player crew ignores items in outposts
|
||||
if (character.IsOnPlayerTeam && item.Submarine.Info.IsOutpost) { return false; }
|
||||
|
||||
@@ -234,8 +234,6 @@ namespace Barotrauma
|
||||
new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }),
|
||||
null, 1.0f, "foundwoundedtarget" + targetCharacter.Name, 60.0f);
|
||||
}
|
||||
|
||||
character.SelectCharacter(targetCharacter);
|
||||
}
|
||||
GiveTreatment(deltaTime);
|
||||
}
|
||||
@@ -268,6 +266,8 @@ namespace Barotrauma
|
||||
}
|
||||
treatmentTimer = TreatmentDelay;
|
||||
|
||||
float cprSuitability = targetCharacter.Oxygen < 0.0f ? -targetCharacter.Oxygen * 100.0f : 0.0f;
|
||||
|
||||
//find which treatments are the most suitable to treat the character's current condition
|
||||
targetCharacter.CharacterHealth.GetSuitableTreatments(currentTreatmentSuitabilities, normalize: false);
|
||||
|
||||
@@ -282,6 +282,7 @@ namespace Barotrauma
|
||||
{
|
||||
Item matchingItem = character.Inventory.FindItemByIdentifier(treatmentSuitability.Key, true);
|
||||
if (matchingItem == null) { continue; }
|
||||
character.SelectCharacter(targetCharacter);
|
||||
ApplyTreatment(affliction, matchingItem);
|
||||
//wait a bit longer after applying a treatment to wait for potential side-effects to manifest
|
||||
treatmentTimer = TreatmentDelay * 4;
|
||||
@@ -292,7 +293,6 @@ namespace Barotrauma
|
||||
// Find treatments outside of own inventory only if inside the own sub.
|
||||
if (character.Submarine != null && character.Submarine.TeamID == character.TeamID)
|
||||
{
|
||||
float cprSuitability = targetCharacter.Oxygen < 0.0f ? -targetCharacter.Oxygen * 100.0f : 0.0f;
|
||||
//didn't have any suitable treatments available, try to find some medical items
|
||||
if (currentTreatmentSuitabilities.Any(s => s.Value > cprSuitability))
|
||||
{
|
||||
@@ -329,7 +329,6 @@ namespace Barotrauma
|
||||
new string[2] { targetCharacter.Name, itemListStr }, new bool[2] { false, true }),
|
||||
null, 2.0f, "listrequiredtreatments" + targetCharacter.Name, 60.0f);
|
||||
}
|
||||
character.DeselectCharacter();
|
||||
RemoveSubObjective(ref getItemObjective);
|
||||
TryAddSubObjective(ref getItemObjective,
|
||||
constructor: () => new AIObjectiveGetItem(character, suitableItemIdentifiers.ToArray(), objectiveManager, equip: true, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC),
|
||||
@@ -345,9 +344,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!targetCharacter.IsUnconscious)
|
||||
{
|
||||
//no suitable treatments found, not inside our own sub (= can't search for more treatments), the target isn't unconscious (= can't give CPR)
|
||||
// -> abandon
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
if (character != targetCharacter)
|
||||
{
|
||||
character.AnimController.Anim = AnimController.Animation.CPR;
|
||||
if (cprSuitability > 0.0f)
|
||||
{
|
||||
character.SelectCharacter(targetCharacter);
|
||||
character.AnimController.Anim = AnimController.Animation.CPR;
|
||||
}
|
||||
else
|
||||
{
|
||||
character.DeselectCharacter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Barotrauma
|
||||
allItems = Wreck.GetItems(false);
|
||||
thalamusItems = allItems.FindAll(i => IsThalamus(i.prefab));
|
||||
hulls.AddRange(Wreck.GetHulls(false));
|
||||
var potentialBrainHulls = new Dictionary<Hull, float>();
|
||||
var potentialBrainHulls = new List<(Hull hull, float weight)>();
|
||||
brain = new Item(brainPrefab, Vector2.Zero, Wreck);
|
||||
thalamusItems.Add(brain);
|
||||
Point minSize = brain.Rect.Size.Multiply(brain.Scale);
|
||||
@@ -100,10 +100,10 @@ namespace Barotrauma
|
||||
}
|
||||
if (weight > 0)
|
||||
{
|
||||
potentialBrainHulls.TryAdd(hull, weight);
|
||||
potentialBrainHulls.Add((hull, weight));
|
||||
}
|
||||
}
|
||||
Hull brainHull = ToolBox.SelectWeightedRandom(potentialBrainHulls.Keys.ToList(), potentialBrainHulls.Values.ToList(), Rand.RandSync.Server);
|
||||
Hull brainHull = ToolBox.SelectWeightedRandom(potentialBrainHulls.Select(pbh => pbh.hull).ToList(), potentialBrainHulls.Select(pbh => pbh.weight).ToList(), Rand.RandSync.Server);
|
||||
var thalamusStructurePrefabs = StructurePrefab.Prefabs.Where(p => IsThalamus(p));
|
||||
if (brainHull == null)
|
||||
{
|
||||
@@ -187,8 +187,11 @@ namespace Barotrauma
|
||||
if (!spawnOrgans.Contains(item))
|
||||
{
|
||||
spawnOrgans.Add(item);
|
||||
// Try to flood the hull so that the spawner won't die.
|
||||
item.CurrentHull.WaterVolume = item.CurrentHull.Volume;
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
// Try to flood the hull so that the spawner won't die.
|
||||
item.CurrentHull.WaterVolume = item.CurrentHull.Volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,16 @@ namespace Barotrauma
|
||||
public enum Animation { None, Climbing, UsingConstruction, Struggle, CPR };
|
||||
public Animation Anim;
|
||||
|
||||
public Vector2 AimSourceWorldPos
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector2 sourcePos = character.AnimController.AimSourcePos;
|
||||
if (character.Submarine != null) { sourcePos += character.Submarine.Position; }
|
||||
return sourcePos;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 AimSourcePos => ConvertUnits.ToDisplayUnits(AimSourceSimPos);
|
||||
public virtual Vector2 AimSourceSimPos => Collider.SimPosition;
|
||||
|
||||
|
||||
@@ -1463,7 +1463,7 @@ namespace Barotrauma
|
||||
target.CharacterHealth.CalculateVitality();
|
||||
if (wasCritical && target.Vitality > 0.0f && Timing.TotalTime > lastReviveTime + 10.0f)
|
||||
{
|
||||
character.Info.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive, character.Position + Vector2.UnitY * 150.0f);
|
||||
character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive, character.Position + Vector2.UnitY * 150.0f);
|
||||
SteamAchievementManager.OnCharacterRevived(target, character);
|
||||
lastReviveTime = (float)Timing.TotalTime;
|
||||
#if SERVER
|
||||
|
||||
@@ -576,7 +576,7 @@ namespace Barotrauma
|
||||
get { return pressureProtection; }
|
||||
set
|
||||
{
|
||||
pressureProtection = Math.Max(value, 0.0f);
|
||||
pressureProtection = Math.Max(value, pressureProtection);
|
||||
pressureProtectionLastSet = Timing.TotalTime;
|
||||
}
|
||||
}
|
||||
@@ -882,6 +882,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInFriendlySub => Submarine != null && Submarine.TeamID == TeamID;
|
||||
|
||||
public delegate void OnDeathHandler(Character character, CauseOfDeath causeOfDeath);
|
||||
public OnDeathHandler OnDeath;
|
||||
|
||||
@@ -2065,10 +2067,9 @@ namespace Barotrauma
|
||||
if (!CanInteract || inventory.Locked) { return false; }
|
||||
|
||||
//the inventory belongs to some other character
|
||||
if (inventory.Owner is Character && inventory.Owner != this)
|
||||
if (inventory.Owner is Character character && inventory.Owner != this)
|
||||
{
|
||||
var owner = (Character)inventory.Owner;
|
||||
|
||||
var owner = character;
|
||||
//can only be accessed if the character is incapacitated and has been selected
|
||||
return SelectedCharacter == owner && owner.CanInventoryBeAccessed;
|
||||
}
|
||||
@@ -2361,7 +2362,7 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
if (isLocalPlayer)
|
||||
{
|
||||
if (!IsMouseOnUI)
|
||||
if (!IsMouseOnUI && (ViewTarget == null || ViewTarget == this))
|
||||
{
|
||||
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
@@ -2832,7 +2833,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (Timing.TotalTime > pressureProtectionLastSet + 0.1)
|
||||
{
|
||||
PressureProtection = 0.0f;
|
||||
pressureProtection = 0.0f;
|
||||
}
|
||||
}
|
||||
if (NeedsWater)
|
||||
@@ -2994,10 +2995,7 @@ namespace Barotrauma
|
||||
{
|
||||
despawnTimer = GameMain.Config.CorpseDespawnDelay;
|
||||
UpdateDespawn(1.0f, ignoreThresholds: true);
|
||||
if (createNetworkEvents)
|
||||
{
|
||||
Spawner.Update();
|
||||
}
|
||||
Spawner.Update(createNetworkEvents);
|
||||
}
|
||||
|
||||
public static void RemoveByPrefab(CharacterPrefab prefab)
|
||||
@@ -3526,6 +3524,7 @@ namespace Barotrauma
|
||||
}
|
||||
bool wasDead = IsDead;
|
||||
Vector2 simPos = hitLimb.SimPosition + ConvertUnits.ToSimUnits(dir);
|
||||
float prevVitality = CharacterHealth.Vitality;
|
||||
AttackResult attackResult = hitLimb.AddDamage(simPos, afflictions, playSound, damageMultiplier: damageMultiplier, penetration: penetration);
|
||||
CharacterHealth.ApplyDamage(hitLimb, attackResult, allowStacking);
|
||||
if (attacker != this)
|
||||
@@ -3534,7 +3533,7 @@ namespace Barotrauma
|
||||
OnAttackedProjSpecific(attacker, attackResult, stun);
|
||||
if (!wasDead)
|
||||
{
|
||||
TryAdjustAttackerSkill(attacker, -attackResult.Damage);
|
||||
TryAdjustAttackerSkill(attacker, CharacterHealth.Vitality - prevVitality);
|
||||
if (IsDead)
|
||||
{
|
||||
attacker?.RecordKill(this);
|
||||
@@ -4001,7 +4000,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
canBePutInOriginalInventory = inventory.CanBePut(newItem, slotIndices[0]);
|
||||
canBePutInOriginalInventory = inventory.CanBePut(newItem, slotIndices[0], ignoreCondition: true);
|
||||
}
|
||||
|
||||
if (canBePutInOriginalInventory)
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Barotrauma
|
||||
State = InfectionState.Final;
|
||||
ActivateHusk();
|
||||
ApplyDamage(deltaTime, applyForce: true);
|
||||
character.SetStun(1);
|
||||
character.SetStun(5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
OnFire, InWater, NotInWater,
|
||||
OnImpact,
|
||||
OnEating,
|
||||
OnDeath = OnBroken,
|
||||
OnDamaged,
|
||||
OnSevered,
|
||||
OnProduceSpawned,
|
||||
OnOpen, OnClose,
|
||||
OnDeath = OnBroken,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace Barotrauma
|
||||
[Serialize("", true)]
|
||||
public string NPCTag { get; set; }
|
||||
|
||||
[Serialize(0, true)]
|
||||
public int TeamTag { get; set; }
|
||||
[Serialize(CharacterTeamType.None, true)]
|
||||
public CharacterTeamType TeamTag { get; set; }
|
||||
|
||||
[Serialize(false, true)]
|
||||
public bool AddToCrew { get; set; }
|
||||
@@ -29,11 +29,10 @@ namespace Barotrauma
|
||||
affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList();
|
||||
foreach (var npc in affectedNpcs)
|
||||
{
|
||||
CharacterTeamType newTeam = (CharacterTeamType)TeamTag;
|
||||
// characters will still remain on friendlyNPC team for rest of the tick
|
||||
npc.SetOriginalTeam(newTeam);
|
||||
npc.SetOriginalTeam(TeamTag);
|
||||
|
||||
if (AddToCrew && (newTeam == CharacterTeamType.Team1 || newTeam == CharacterTeamType.Team2))
|
||||
if (AddToCrew && (TeamTag == CharacterTeamType.Team1 || TeamTag == CharacterTeamType.Team2))
|
||||
{
|
||||
npc.Info.StartItemsGiven = true;
|
||||
|
||||
@@ -44,11 +43,11 @@ namespace Barotrauma
|
||||
var wifiComponent = item.GetComponent<Items.Components.WifiComponent>();
|
||||
if (wifiComponent != null)
|
||||
{
|
||||
wifiComponent.TeamID = newTeam;
|
||||
wifiComponent.TeamID = TeamTag;
|
||||
}
|
||||
}
|
||||
#if SERVER
|
||||
GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AddToCrew, newTeam, npc.Inventory.AllItems.Select(it => it.ID).ToArray() });
|
||||
GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AddToCrew, TeamTag, npc.Inventory.AllItems.Select(it => it.ID).ToArray() });
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,13 +124,24 @@ namespace Barotrauma
|
||||
}
|
||||
MTRandom rand = new MTRandom(seed);
|
||||
|
||||
var initialEventSet = SelectRandomEvents(EventSet.List, rand);
|
||||
EventSet initialEventSet = SelectRandomEvents(EventSet.List, rand);
|
||||
EventSet additiveSet = null;
|
||||
if (initialEventSet != null && initialEventSet.Additive)
|
||||
{
|
||||
additiveSet = initialEventSet;
|
||||
initialEventSet = SelectRandomEvents(EventSet.List.FindAll(e => !e.Additive), rand);
|
||||
}
|
||||
if (initialEventSet != null)
|
||||
{
|
||||
pendingEventSets.Add(initialEventSet);
|
||||
CreateEvents(initialEventSet, rand);
|
||||
}
|
||||
|
||||
if (additiveSet != null)
|
||||
{
|
||||
pendingEventSets.Add(additiveSet);
|
||||
CreateEvents(additiveSet, rand);
|
||||
}
|
||||
|
||||
if (level?.LevelData?.Type == LevelData.LevelType.Outpost)
|
||||
{
|
||||
//if the outpost is connected to a locked connection, create an event to unlock it
|
||||
|
||||
@@ -94,6 +94,8 @@ namespace Barotrauma
|
||||
|
||||
public readonly bool TriggerEventCooldown;
|
||||
|
||||
public readonly bool Additive;
|
||||
|
||||
public readonly Dictionary<string, float> Commonness;
|
||||
|
||||
public readonly List<(EventPrefab prefab, float commonness, float probability)> EventPrefabs;
|
||||
@@ -117,6 +119,8 @@ namespace Barotrauma
|
||||
MinLevelDifficulty = element.GetAttributeFloat("minleveldifficulty", 0);
|
||||
MaxLevelDifficulty = Math.Max(element.GetAttributeFloat("maxleveldifficulty", 100), MinLevelDifficulty);
|
||||
|
||||
Additive = element.GetAttributeBool("additive", false);
|
||||
|
||||
string levelTypeStr = element.GetAttributeString("leveltype", "LocationConnection");
|
||||
if (!Enum.TryParse(levelTypeStr, true, out LevelType))
|
||||
{
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace Barotrauma
|
||||
|
||||
private Submarine sub;
|
||||
|
||||
private readonly List<CargoMission> previouslySelectedMissions = new List<CargoMission>();
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
@@ -42,7 +44,13 @@ namespace Barotrauma
|
||||
{
|
||||
this.sub = sub;
|
||||
itemConfig = prefab.ConfigElement.Element("Items");
|
||||
requiredDeliveryAmount = Math.Min(prefab.ConfigElement.GetAttributeFloat("requireddeliveryamount", 0.98f), 1.0f);
|
||||
requiredDeliveryAmount = Math.Min(prefab.ConfigElement.GetAttributeFloat("requireddeliveryamount", 0.98f), 1.0f);
|
||||
//this can get called between rounds when the client receives a campaign save
|
||||
//don't attempt to determine cargo if the sub hasn't been fully loaded
|
||||
if (sub == null || sub.Loading || sub.Removed || Submarine.Unloading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DetermineCargo();
|
||||
}
|
||||
|
||||
@@ -58,6 +66,30 @@ namespace Barotrauma
|
||||
List<(ItemContainer container, int freeSlots)> containers = sub.GetCargoContainers();
|
||||
containers.Sort((c1, c2) => { return c2.container.Capacity.CompareTo(c1.container.Capacity); });
|
||||
|
||||
previouslySelectedMissions.Clear();
|
||||
if (GameMain.GameSession?.StartLocation?.SelectedMissions != null)
|
||||
{
|
||||
bool isPriorMission = true;
|
||||
foreach (Mission mission in GameMain.GameSession.StartLocation.SelectedMissions)
|
||||
{
|
||||
if (!(mission is CargoMission otherMission)) { continue; }
|
||||
if (mission == this) { isPriorMission = false; }
|
||||
previouslySelectedMissions.Add(otherMission);
|
||||
if (!isPriorMission) { continue; }
|
||||
foreach (var (element, container) in otherMission.itemsToSpawn)
|
||||
{
|
||||
for (int i = 0; i < containers.Count; i++)
|
||||
{
|
||||
if (containers[i].container == container)
|
||||
{
|
||||
containers[i] = (containers[i].container, containers[i].freeSlots - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maxItemCount = 0;
|
||||
foreach (XElement subElement in itemConfig.Elements())
|
||||
{
|
||||
@@ -87,9 +119,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
calculatedReward = 0;
|
||||
foreach (var itemToSpawn in itemsToSpawn)
|
||||
foreach (var (element, container) in itemsToSpawn)
|
||||
{
|
||||
int price = itemToSpawn.element.GetAttributeInt("reward", Prefab.Reward / itemsToSpawn.Count);
|
||||
int price = element.GetAttributeInt("reward", Prefab.Reward / itemsToSpawn.Count);
|
||||
if (rewardPerCrate.HasValue)
|
||||
{
|
||||
if (price != rewardPerCrate.Value) { rewardPerCrate = -1; }
|
||||
@@ -108,7 +140,28 @@ namespace Barotrauma
|
||||
|
||||
public override int GetReward(Submarine sub)
|
||||
{
|
||||
if (sub != this.sub)
|
||||
bool missionsChanged = false;
|
||||
if (GameMain.GameSession?.StartLocation?.SelectedMissions != null)
|
||||
{
|
||||
List<Mission> currentMissions = GameMain.GameSession.StartLocation.SelectedMissions.Where(m => m is CargoMission).ToList();
|
||||
if (currentMissions.Count != previouslySelectedMissions.Count)
|
||||
{
|
||||
missionsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < previouslySelectedMissions.Count; i++)
|
||||
{
|
||||
if (previouslySelectedMissions[i] != currentMissions[i])
|
||||
{
|
||||
missionsChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sub != this.sub || missionsChanged)
|
||||
{
|
||||
this.sub = sub;
|
||||
DetermineCargo();
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetDifficulty(float difficulty) { }
|
||||
public virtual void SetLevel(LevelData level) { }
|
||||
|
||||
public static Mission LoadRandom(Location[] locations, string seed, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer = false)
|
||||
{
|
||||
@@ -423,13 +423,16 @@ namespace Barotrauma
|
||||
|
||||
protected Character CreateHuman(HumanPrefab humanPrefab, List<Character> characters, Dictionary<Character, List<Item>> characterItems, Submarine submarine, CharacterTeamType teamType, ISpatialEntity positionToStayIn = null, Rand.RandSync humanPrefabRandSync = Rand.RandSync.Server, bool giveTags = true)
|
||||
{
|
||||
if (positionToStayIn == null)
|
||||
{
|
||||
positionToStayIn = WayPoint.GetRandom(SpawnType.Human, null, submarine);
|
||||
}
|
||||
|
||||
var characterInfo = humanPrefab.GetCharacterInfo(Rand.RandSync.Server) ?? new CharacterInfo(CharacterPrefab.HumanSpeciesName, npcIdentifier: humanPrefab.Identifier, jobPrefab: humanPrefab.GetJobPrefab(humanPrefabRandSync), randSync: humanPrefabRandSync);
|
||||
characterInfo.TeamID = teamType;
|
||||
|
||||
if (positionToStayIn == null)
|
||||
{
|
||||
positionToStayIn =
|
||||
WayPoint.GetRandom(SpawnType.Human, characterInfo.Job?.Prefab, submarine) ??
|
||||
WayPoint.GetRandom(SpawnType.Human, null, submarine);
|
||||
}
|
||||
|
||||
Character spawnedCharacter = Character.Create(characterInfo.SpeciesName, positionToStayIn.WorldPosition, ToolBox.RandomSeed(8), characterInfo, createNetworkEvent: false);
|
||||
spawnedCharacter.Prefab = humanPrefab;
|
||||
humanPrefab.InitializeCharacter(spawnedCharacter, positionToStayIn);
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace Barotrauma
|
||||
//ruin/cave/wreck items are allowed to spawn close to the sub
|
||||
float minDistance = spawnPositionType == Level.PositionType.Ruin || spawnPositionType == Level.PositionType.Cave || spawnPositionType == Level.PositionType.Wreck ?
|
||||
0.0f : Level.Loaded.Size.X * 0.3f;
|
||||
nestPosition = Level.Loaded.GetRandomItemPos(spawnPositionType, 100.0f, minDistance, 30.0f);
|
||||
Level.Loaded.TryGetInterestingPosition(true, spawnPositionType, 0.0f, out Vector2 nestPosition);
|
||||
List<GraphEdge> spawnEdges = new List<GraphEdge>();
|
||||
if (spawnPositionType == Level.PositionType.Cave)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Barotrauma
|
||||
private float pirateSightingUpdateTimer;
|
||||
private Vector2? lastSighting;
|
||||
|
||||
private LevelData levelData;
|
||||
|
||||
public override int TeamCount => 2;
|
||||
|
||||
private bool outsideOfSonarRange;
|
||||
@@ -83,21 +85,24 @@ namespace Barotrauma
|
||||
characterTypeConfig = prefab.ConfigElement.Element("CharacterTypes");
|
||||
addedMissionDifficultyPerPlayer = prefab.ConfigElement.GetAttributeFloat("addedmissiondifficultyperplayer", 0);
|
||||
|
||||
// for campaign missions, set difficulty at construction
|
||||
// for campaign missions, set level at construction
|
||||
LevelData levelData = locations[0].Connections.Where(c => c.Locations.Contains(locations[1])).FirstOrDefault()?.LevelData ?? locations[0]?.LevelData;
|
||||
|
||||
SetDifficulty(levelData?.Difficulty ?? Level.Loaded?.Difficulty ?? 0f);
|
||||
if (levelData != null)
|
||||
{
|
||||
SetLevel(levelData);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetDifficulty(float difficulty)
|
||||
public override void SetLevel(LevelData level)
|
||||
{
|
||||
if (missionDifficulty > 0f)
|
||||
if (levelData != null)
|
||||
{
|
||||
// difficulty already set
|
||||
//level already set
|
||||
return;
|
||||
}
|
||||
|
||||
missionDifficulty = difficulty;
|
||||
levelData = level;
|
||||
missionDifficulty = level?.Difficulty ?? 0;
|
||||
|
||||
XElement submarineConfig = GetRandomDifficultyModifiedElement(submarineTypeConfig, missionDifficulty, ShipRandomnessModifier);
|
||||
|
||||
@@ -123,23 +128,24 @@ namespace Barotrauma
|
||||
submarineInfo = new SubmarineInfo(contentFile.Path);
|
||||
}
|
||||
|
||||
private float GetDifficultyModifiedValue(float preferredDifficulty, float levelDifficulty, float randomnessModifier)
|
||||
private float GetDifficultyModifiedValue(float preferredDifficulty, float levelDifficulty, float randomnessModifier, Random rand)
|
||||
{
|
||||
return Math.Abs(levelDifficulty - preferredDifficulty + (Rand.Range(-randomnessModifier, randomnessModifier, Rand.RandSync.Server)));
|
||||
return Math.Abs(levelDifficulty - preferredDifficulty + MathHelper.Lerp(-randomnessModifier, randomnessModifier, (float)rand.NextDouble()));
|
||||
}
|
||||
private int GetDifficultyModifiedAmount(int minAmount, int maxAmount, float levelDifficulty)
|
||||
private int GetDifficultyModifiedAmount(int minAmount, int maxAmount, float levelDifficulty, Random rand)
|
||||
{
|
||||
return Math.Max((int)Math.Round(minAmount + (maxAmount - minAmount) * ((levelDifficulty + Rand.Range(-RandomnessModifier, RandomnessModifier, Rand.RandSync.Server)) / MaxDifficulty)), minAmount);
|
||||
return Math.Max((int)Math.Round(minAmount + (maxAmount - minAmount) * (levelDifficulty + MathHelper.Lerp(-RandomnessModifier, RandomnessModifier, (float)rand.NextDouble())) / MaxDifficulty), minAmount);
|
||||
}
|
||||
|
||||
private XElement GetRandomDifficultyModifiedElement(XElement parentElement, float levelDifficulty, float randomnessModifier)
|
||||
{
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
// look for the element that is closest to our difficulty, with some randomness
|
||||
XElement bestElement = null;
|
||||
float bestValue = float.MaxValue;
|
||||
foreach (XElement element in parentElement.Elements())
|
||||
{
|
||||
float applicabilityValue = GetDifficultyModifiedValue(element.GetAttributeFloat(0f, "preferreddifficulty"), levelDifficulty, randomnessModifier);
|
||||
float applicabilityValue = GetDifficultyModifiedValue(element.GetAttributeFloat(0f, "preferreddifficulty"), levelDifficulty, randomnessModifier, rand);
|
||||
if (applicabilityValue < bestValue)
|
||||
{
|
||||
bestElement = element;
|
||||
@@ -154,11 +160,11 @@ namespace Barotrauma
|
||||
Vector2 patrolPos = enemySub.WorldPosition;
|
||||
Point subSize = enemySub.GetDockedBorders().Size;
|
||||
|
||||
if (!Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath | Level.PositionType.SidePath, Level.Loaded.Size.X * 0.3f, out preferredSpawnPos))
|
||||
if (!Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out preferredSpawnPos))
|
||||
{
|
||||
DebugConsole.ThrowError("Could not spawn pirate submarine in an interesting location! " + this);
|
||||
}
|
||||
if (!Level.Loaded.TryGetInterestingPositionAwayFromPoint(true, Level.PositionType.MainPath | Level.PositionType.SidePath, Level.Loaded.Size.X * 0.3f, out patrolPos, preferredSpawnPos, minDistFromPoint: 10000f))
|
||||
if (!Level.Loaded.TryGetInterestingPositionAwayFromPoint(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out patrolPos, preferredSpawnPos, minDistFromPoint: 10000f))
|
||||
{
|
||||
DebugConsole.ThrowError("Could not give pirate submarine an interesting location to patrol to! " + this);
|
||||
}
|
||||
@@ -182,7 +188,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void InitPirateShip(Vector2 spawnPos)
|
||||
private void InitPirateShip()
|
||||
{
|
||||
enemySub.NeutralizeBallast();
|
||||
if (enemySub.GetItems(alsoFromConnectedSubs: false).Find(i => i.HasTag("reactor") && !i.NonInteractable)?.GetComponent<Reactor>() is Reactor reactor)
|
||||
@@ -193,6 +199,7 @@ namespace Barotrauma
|
||||
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);
|
||||
enemySub.ImmuneToBallastFlora = true;
|
||||
}
|
||||
|
||||
private void InitPirates()
|
||||
@@ -214,12 +221,14 @@ namespace Barotrauma
|
||||
|
||||
float enemyCreationDifficulty = missionDifficulty + playerCount * addedMissionDifficultyPerPlayer;
|
||||
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
|
||||
bool commanderAssigned = false;
|
||||
foreach (XElement element in characterConfig.Elements())
|
||||
{
|
||||
// it is possible to get more than the "max" amount of characters if the modified difficulty is high enough; this is intentional
|
||||
// if necessary, another "hard max" value could be used to clamp the value for performance/gameplay concerns
|
||||
int amountCreated = GetDifficultyModifiedAmount(element.GetAttributeInt("minamount", 0), element.GetAttributeInt("maxamount", 0), enemyCreationDifficulty);
|
||||
int amountCreated = GetDifficultyModifiedAmount(element.GetAttributeInt("minamount", 0), element.GetAttributeInt("maxamount", 0), enemyCreationDifficulty, rand);
|
||||
for (int i = 0; i < amountCreated; i++)
|
||||
{
|
||||
XElement characterType = characterTypeConfig.Elements().Where(e => e.GetAttributeString("typeidentifier", string.Empty) == element.GetAttributeString("typeidentifier", string.Empty)).FirstOrDefault();
|
||||
@@ -307,7 +316,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
if (!IsClient)
|
||||
{
|
||||
InitPirateShip(spawnPos);
|
||||
InitPirateShip();
|
||||
}
|
||||
enemySub.SetPosition(spawnPos);
|
||||
|
||||
|
||||
@@ -651,6 +651,7 @@ namespace Barotrauma
|
||||
location.ClearMissions();
|
||||
location.Discovered = false;
|
||||
location.LevelData?.EventHistory?.Clear();
|
||||
location.UnlockInitialMissions();
|
||||
}
|
||||
Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation));
|
||||
Map.SelectLocation(-1);
|
||||
@@ -700,7 +701,7 @@ namespace Barotrauma
|
||||
if (npc == null || interactor == null) { yield return CoroutineStatus.Failure; }
|
||||
|
||||
HumanAIController humanAI = npc.AIController as HumanAIController;
|
||||
if (humanAI == null) { yield return CoroutineStatus.Failure; }
|
||||
if (humanAI == null) { yield return CoroutineStatus.Success; }
|
||||
|
||||
var waitOrder = Order.PrefabList.Find(o => o.Identifier.Equals("wait", StringComparison.OrdinalIgnoreCase));
|
||||
humanAI.SetForcedOrder(waitOrder, string.Empty, null);
|
||||
@@ -719,8 +720,10 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
ShowCampaignUI = false;
|
||||
#endif
|
||||
|
||||
humanAI.ClearForcedOrder();
|
||||
if (!npc.Removed)
|
||||
{
|
||||
humanAI.ClearForcedOrder();
|
||||
}
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -729,13 +732,16 @@ namespace Barotrauma
|
||||
public void AssignNPCMenuInteraction(Character character, InteractionType interactionType)
|
||||
{
|
||||
character.CampaignInteractionType = interactionType;
|
||||
if (interactionType == InteractionType.None)
|
||||
character.CharacterHealth.UseHealthWindow =
|
||||
interactionType == InteractionType.None ||
|
||||
interactionType == InteractionType.Examine ||
|
||||
interactionType == InteractionType.Talk;
|
||||
|
||||
if (interactionType == InteractionType.None)
|
||||
{
|
||||
character.SetCustomInteract(null, null);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
character.CharacterHealth.UseHealthWindow = false;
|
||||
//character.CanInventoryBeAccessed = false;
|
||||
character.SetCustomInteract(
|
||||
NPCInteract,
|
||||
#if CLIENT
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -29,20 +30,30 @@ namespace Barotrauma
|
||||
public XElement OrderData { get; private set; }
|
||||
|
||||
partial void InitProjSpecific(Client client);
|
||||
public CharacterCampaignData(Client client)
|
||||
public CharacterCampaignData(Client client, bool giveRespawnPenaltyAffliction = false)
|
||||
{
|
||||
Name = client.Name;
|
||||
InitProjSpecific(client);
|
||||
|
||||
healthData = new XElement("health");
|
||||
client.Character.CharacterHealth.Save(healthData);
|
||||
if (client.Character.Inventory != null)
|
||||
client.Character?.CharacterHealth?.Save(healthData);
|
||||
if (giveRespawnPenaltyAffliction)
|
||||
{
|
||||
var respawnPenaltyAffliction = RespawnManager.GetRespawnPenaltyAffliction();
|
||||
healthData.Add(new XElement("Affliction",
|
||||
new XAttribute("identifier", respawnPenaltyAffliction.Identifier),
|
||||
new XAttribute("strength", respawnPenaltyAffliction.Strength.ToString("G", CultureInfo.InvariantCulture))));
|
||||
}
|
||||
if (client.Character?.Inventory != null)
|
||||
{
|
||||
itemData = new XElement("inventory");
|
||||
Character.SaveInventory(client.Character.Inventory, itemData);
|
||||
}
|
||||
OrderData = new XElement("orders");
|
||||
CharacterInfo.SaveOrderData(client.Character.Info, OrderData);
|
||||
if (client.Character != null)
|
||||
{
|
||||
CharacterInfo.SaveOrderData(client.Character.Info, OrderData);
|
||||
}
|
||||
}
|
||||
|
||||
public CharacterCampaignData(XElement element)
|
||||
|
||||
@@ -368,8 +368,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (Mission mission in GameMode.Missions)
|
||||
{
|
||||
// setting difficulty for missions that may involve difficulty-related submarine creation
|
||||
mission.SetDifficulty(levelData?.Difficulty ?? 0f);
|
||||
// setting level for missions that may involve difficulty-related submarine creation
|
||||
mission.SetLevel(levelData);
|
||||
}
|
||||
|
||||
if (Submarine.MainSubs[1] == null)
|
||||
|
||||
@@ -296,10 +296,12 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
var linkedItems = GetLinkedItemsToSwap(itemToRemove);
|
||||
|
||||
int price = 0;
|
||||
if (!itemToRemove.AvailableSwaps.Contains(itemToInstall))
|
||||
{
|
||||
price = itemToInstall.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation);
|
||||
price = itemToInstall.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation) * linkedItems.Count;
|
||||
}
|
||||
|
||||
if (force)
|
||||
@@ -309,7 +311,7 @@ namespace Barotrauma
|
||||
|
||||
if (Campaign.Money >= price)
|
||||
{
|
||||
PurchasedItemSwaps.RemoveAll(p => p.ItemToRemove == itemToRemove);
|
||||
PurchasedItemSwaps.RemoveAll(p => linkedItems.Contains(p.ItemToRemove));
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
// only make the NPC speak if more than 5 minutes have passed since the last purchased service
|
||||
@@ -322,23 +324,27 @@ namespace Barotrauma
|
||||
|
||||
Campaign.Money -= price;
|
||||
|
||||
itemToRemove.AvailableSwaps.Add(itemToRemove.Prefab);
|
||||
if (itemToInstall != null && !itemToRemove.AvailableSwaps.Contains(itemToInstall))
|
||||
foreach (Item itemToSwap in linkedItems)
|
||||
{
|
||||
itemToRemove.PurchasedNewSwap = true;
|
||||
itemToRemove.AvailableSwaps.Add(itemToInstall);
|
||||
itemToSwap.AvailableSwaps.Add(itemToSwap.Prefab);
|
||||
if (itemToInstall != null && !itemToSwap.AvailableSwaps.Contains(itemToInstall))
|
||||
{
|
||||
itemToSwap.PurchasedNewSwap = true;
|
||||
itemToSwap.AvailableSwaps.Add(itemToInstall);
|
||||
}
|
||||
|
||||
if (itemToSwap.Prefab != itemToInstall && itemToInstall != null)
|
||||
{
|
||||
itemToSwap.PendingItemSwap = itemToInstall;
|
||||
PurchasedItemSwaps.Add(new PurchasedItemSwap(itemToSwap, itemToInstall));
|
||||
DebugLog($"CLIENT: Swapped item \"{itemToSwap.Name}\" with \"{itemToInstall.Name}\".", Color.Orange);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog($"CLIENT: Cancelled swapping the item \"{itemToSwap.Name}\" with \"{(itemToSwap.PendingItemSwap?.Name ?? null)}\".", Color.Orange);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemToRemove.Prefab != itemToInstall && itemToInstall != null)
|
||||
{
|
||||
itemToRemove.PendingItemSwap = itemToInstall;
|
||||
PurchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||
DebugLog($"CLIENT: Swapped item \"{itemToRemove.Name}\" with \"{itemToInstall.Name}\".", Color.Orange);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog($"CLIENT: Cancelled swapping the item \"{itemToRemove.Name}\" with \"{(itemToRemove.PendingItemSwap?.Name ?? null)}\".", Color.Orange);
|
||||
}
|
||||
OnUpgradesChanged?.Invoke();
|
||||
}
|
||||
else
|
||||
@@ -382,30 +388,55 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (itemToRemove.PendingItemSwap == null)
|
||||
var linkedItems = GetLinkedItemsToSwap(itemToRemove);
|
||||
|
||||
foreach (Item itemToCancel in linkedItems)
|
||||
{
|
||||
var replacement = MapEntityPrefab.Find("", swappableItem.ReplacementOnUninstall) as ItemPrefab;
|
||||
if (replacement == null)
|
||||
if (itemToCancel.PendingItemSwap == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to uninstall item \"{itemToRemove.Name}\". Could not find the replacement item \"{swappableItem.ReplacementOnUninstall}\".");
|
||||
return;
|
||||
var replacement = MapEntityPrefab.Find("", swappableItem.ReplacementOnUninstall) as ItemPrefab;
|
||||
if (replacement == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to uninstall item \"{itemToCancel.Name}\". Could not find the replacement item \"{swappableItem.ReplacementOnUninstall}\".");
|
||||
return;
|
||||
}
|
||||
PurchasedItemSwaps.RemoveAll(p => p.ItemToRemove == itemToCancel);
|
||||
PurchasedItemSwaps.Add(new PurchasedItemSwap(itemToCancel, replacement));
|
||||
DebugLog($"Uninstalled item item \"{itemToCancel.Name}\".", Color.Orange);
|
||||
itemToCancel.PendingItemSwap = replacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
PurchasedItemSwaps.RemoveAll(p => p.ItemToRemove == itemToCancel);
|
||||
DebugLog($"Cancelled swapping the item \"{itemToCancel.Name}\" with \"{itemToCancel.PendingItemSwap.Name}\".", Color.Orange);
|
||||
itemToCancel.PendingItemSwap = null;
|
||||
}
|
||||
PurchasedItemSwaps.RemoveAll(p => p.ItemToRemove == itemToRemove);
|
||||
PurchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, replacement));
|
||||
DebugLog($"Uninstalled item item \"{itemToRemove.Name}\".", Color.Orange);
|
||||
itemToRemove.PendingItemSwap = replacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
PurchasedItemSwaps.RemoveAll(p => p.ItemToRemove == itemToRemove);
|
||||
DebugLog($"Cancelled swapping the item \"{itemToRemove.Name}\" with \"{itemToRemove.PendingItemSwap.Name}\".", Color.Orange);
|
||||
itemToRemove.PendingItemSwap = null;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
OnUpgradesChanged?.Invoke();
|
||||
#endif
|
||||
}
|
||||
|
||||
public List<Item> GetLinkedItemsToSwap(Item item)
|
||||
{
|
||||
List<Item> linkedItems = new List<Item>() { item };
|
||||
foreach (MapEntity linkedEntity in item.linkedTo)
|
||||
{
|
||||
foreach (MapEntity secondLinkedEntity in linkedEntity.linkedTo)
|
||||
{
|
||||
if (!(secondLinkedEntity is Item linkedItem) || linkedItem == item) { continue; }
|
||||
if (linkedItem.AllowSwapping &&
|
||||
linkedItem.Prefab.SwappableItem != null && linkedItem.Prefab.SwappableItem.CanBeBought &&
|
||||
linkedItem.Prefab.SwappableItem.SwapIdentifier.Equals(item.Prefab.SwappableItem.SwapIdentifier, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
linkedItems.Add(linkedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return linkedItems;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies all our pending upgrades to the submarine.
|
||||
/// </summary>
|
||||
@@ -565,7 +596,7 @@ namespace Barotrauma
|
||||
/// <param name="submarine"></param>
|
||||
/// <param name="level"></param>
|
||||
/// <returns>New level that was applied, -1 if no upgrades were applied.</returns>
|
||||
private static int BuyUpgrade(UpgradePrefab prefab, UpgradeCategory category, Submarine submarine, int level = 1)
|
||||
private static int BuyUpgrade(UpgradePrefab prefab, UpgradeCategory category, Submarine submarine, int level = 1, Submarine parentSub = null)
|
||||
{
|
||||
int? newLevel = null;
|
||||
if (category.IsWallUpgrade)
|
||||
@@ -604,6 +635,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Submarine loadedSub in Submarine.Loaded.Where(sub => sub != submarine))
|
||||
{
|
||||
if (loadedSub == parentSub) { continue; }
|
||||
XElement? root = loadedSub.Info?.SubmarineElement;
|
||||
if (root == null) { continue; }
|
||||
|
||||
@@ -615,7 +647,7 @@ namespace Barotrauma
|
||||
ushort dockingPortID = (ushort) root.GetAttributeInt("originallinkedto", 0);
|
||||
if (dockingPortID > 0 && submarine.GetItems(true).Any(item => item.ID == dockingPortID))
|
||||
{
|
||||
BuyUpgrade(prefab, category, loadedSub, level);
|
||||
BuyUpgrade(prefab, category, loadedSub, level, submarine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,17 +132,17 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CanBePut(Item item, int i)
|
||||
public override bool CanBePut(Item item, int i, bool ignoreCondition = false)
|
||||
{
|
||||
return
|
||||
base.CanBePut(item, i) && item.AllowedSlots.Any(s => s.HasFlag(SlotTypes[i])) &&
|
||||
base.CanBePut(item, i, ignoreCondition) && item.AllowedSlots.Any(s => s.HasFlag(SlotTypes[i])) &&
|
||||
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
|
||||
}
|
||||
|
||||
public override bool CanBePut(ItemPrefab itemPrefab, int i)
|
||||
public override bool CanBePut(ItemPrefab itemPrefab, int i, float? condition)
|
||||
{
|
||||
return
|
||||
base.CanBePut(itemPrefab, i) &&
|
||||
base.CanBePut(itemPrefab, i, condition) &&
|
||||
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedSlots != null && !allowedSlots.Contains(InvSlotType.Any))
|
||||
if (allowedSlots != null && allowedSlots.Any() && !allowedSlots.Contains(InvSlotType.Any))
|
||||
{
|
||||
bool allSlotsTaken = true;
|
||||
foreach (var allowedSlot in allowedSlots)
|
||||
|
||||
@@ -167,10 +167,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (DockingPort port in list)
|
||||
{
|
||||
if (port == this || port.item.Submarine == item.Submarine) continue;
|
||||
|
||||
if (Math.Abs(port.item.WorldPosition.X - item.WorldPosition.X) > DistanceTolerance.X) continue;
|
||||
if (Math.Abs(port.item.WorldPosition.Y - item.WorldPosition.Y) > DistanceTolerance.Y) continue;
|
||||
if (port == this || port.item.Submarine == item.Submarine || port.IsHorizontal != IsHorizontal) { continue; }
|
||||
if (Math.Abs(port.item.WorldPosition.X - item.WorldPosition.X) > DistanceTolerance.X) { continue; }
|
||||
if (Math.Abs(port.item.WorldPosition.Y - item.WorldPosition.Y) > DistanceTolerance.Y) { continue; }
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
@@ -82,13 +82,13 @@ namespace Barotrauma.Items.Components
|
||||
get { return nodes; }
|
||||
}
|
||||
|
||||
private readonly List<Pair<Character,Node>> charactersInRange = new List<Pair<Character, Node>>();
|
||||
private readonly List<(Character character, Node node)> charactersInRange = new List<(Character character, Node node)>();
|
||||
|
||||
private bool charging;
|
||||
|
||||
private float timer;
|
||||
|
||||
private Attack attack;
|
||||
private readonly Attack attack;
|
||||
|
||||
public ElectricalDischarger(Item item, XElement element) :
|
||||
base(item, element)
|
||||
@@ -114,8 +114,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
//already active, do nothing
|
||||
if (IsActive) { return false; }
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return false; }
|
||||
if (character != null && !CharacterUsable) { return false; }
|
||||
|
||||
CurrPowerConsumption = powerConsumption;
|
||||
charging = true;
|
||||
@@ -182,9 +182,9 @@ namespace Barotrauma.Items.Components
|
||||
FindNodes(item.WorldPosition, Range);
|
||||
if (attack != null)
|
||||
{
|
||||
foreach (Pair<Character, Node> characterInRange in charactersInRange)
|
||||
foreach ((Character character, Node node) in charactersInRange)
|
||||
{
|
||||
characterInRange.First.ApplyAttack(null, characterInRange.Second.WorldPosition, attack, 1.0f);
|
||||
character.ApplyAttack(null, node.WorldPosition, attack, 1.0f);
|
||||
}
|
||||
}
|
||||
DischargeProjSpecific();
|
||||
@@ -315,7 +315,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (closestIndex == -1 || closestDist > currentRange)
|
||||
{
|
||||
int originalParentNodeIndex = parentNodeIndex;
|
||||
//nothing in range, create some arcs to random directions
|
||||
for (int i = 0; i < Rand.Int(4); i++)
|
||||
{
|
||||
@@ -455,7 +454,7 @@ namespace Barotrauma.Items.Components
|
||||
AddNodesBetweenPoints(currPos, targetPos, 0.25f, ref parentNodeIndex);
|
||||
nodes.Add(new Node(targetPos, parentNodeIndex));
|
||||
entitiesInRange.RemoveAt(closestIndex);
|
||||
charactersInRange.Add(new Pair<Character, Node>(character, nodes[parentNodeIndex]));
|
||||
charactersInRange.Add((character, nodes[parentNodeIndex]));
|
||||
FindNodes(entitiesInRange, targetPos, nodes.Count - 1, currentRange);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,7 +678,7 @@ namespace Barotrauma.Items.Components
|
||||
Reset();
|
||||
previousGap = leak;
|
||||
}
|
||||
Vector2 fromCharacterToLeak = leak.WorldPosition - character.WorldPosition;
|
||||
Vector2 fromCharacterToLeak = leak.WorldPosition - character.AnimController.AimSourceWorldPos;
|
||||
float dist = fromCharacterToLeak.Length();
|
||||
float reach = AIObjectiveFixLeak.CalculateReach(this, character);
|
||||
|
||||
@@ -692,10 +692,10 @@ namespace Barotrauma.Items.Components
|
||||
if (!character.AnimController.InWater)
|
||||
{
|
||||
// TODO: use the collider size?
|
||||
if (!character.AnimController.InWater && character.AnimController is HumanoidAnimController &&
|
||||
if (!character.AnimController.InWater && character.AnimController is HumanoidAnimController humanAnim &&
|
||||
Math.Abs(fromCharacterToLeak.X) < 100.0f && fromCharacterToLeak.Y < 0.0f && fromCharacterToLeak.Y > -150.0f)
|
||||
{
|
||||
((HumanoidAnimController)character.AnimController).Crouching = true;
|
||||
humanAnim.Crouching = true;
|
||||
}
|
||||
}
|
||||
if (dist > reach * 0.8f || dist > reach * 0.5f && character.AnimController.Limbs.Any(l => l.inWater))
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool midAir;
|
||||
|
||||
//continuous collision detection is used while the item is moving faster than this
|
||||
const float ContinuousCollisionThreshold = 5.0f;
|
||||
|
||||
public Character CurrentThrower
|
||||
{
|
||||
get;
|
||||
@@ -61,6 +64,13 @@ namespace Barotrauma.Items.Components
|
||||
if (!item.body.Enabled) { return; }
|
||||
if (midAir)
|
||||
{
|
||||
if (item.body.FarseerBody.IsBullet)
|
||||
{
|
||||
if (item.body.LinearVelocity.LengthSquared() < ContinuousCollisionThreshold * ContinuousCollisionThreshold)
|
||||
{
|
||||
item.body.FarseerBody.IsBullet = false;
|
||||
}
|
||||
}
|
||||
if (item.body.LinearVelocity.LengthSquared() < 0.01f)
|
||||
{
|
||||
CurrentThrower = null;
|
||||
@@ -156,6 +166,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//disable platform collisions until the item comes back to rest again
|
||||
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
|
||||
item.body.FarseerBody.IsBullet = true;
|
||||
midAir = true;
|
||||
|
||||
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
@@ -165,6 +176,7 @@ namespace Barotrauma.Items.Components
|
||||
item.body.AngularVelocity = rightHand.body.AngularVelocity;
|
||||
throwPos = 0;
|
||||
throwDone = true;
|
||||
IsActive = true;
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma.Items.Components
|
||||
protected bool canBeCombined;
|
||||
protected bool removeOnCombined;
|
||||
|
||||
public bool WasUsed;
|
||||
public bool WasUsed, WasSecondaryUsed;
|
||||
|
||||
public readonly Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using FarseerPhysics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -60,7 +61,21 @@ namespace Barotrauma.Items.Components
|
||||
Drawable = !hideItems;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
[Editable]
|
||||
#endif
|
||||
[Serialize("0.0,0.0", false, description: "The position where the contained items get drawn at (offset from the upper left corner of the sprite in pixels).")]
|
||||
public Vector2 ItemPos { get; set; }
|
||||
|
||||
#if DEBUG
|
||||
[Editable]
|
||||
#endif
|
||||
[Serialize("0.0,0.0", false, description: "The interval at which the contained items are spaced apart from each other (in pixels).")]
|
||||
public Vector2 ItemInterval { get; set; }
|
||||
[Serialize(100, false, description: "How many items are placed in a row before starting a new row.")]
|
||||
public int ItemsPerRow { get; set; }
|
||||
|
||||
[Serialize(true, false, description: "Should the inventory of this item be visible when the item is selected.")]
|
||||
public bool DrawInventory
|
||||
{
|
||||
@@ -118,6 +133,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false, description: "Should the items configured using SpawnWithId spawn if this item is broken.")]
|
||||
public bool SpawnWithIdWhenBroken
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool RemoveContainedItemsOnDeconstruct { get; set; }
|
||||
|
||||
@@ -335,20 +357,66 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void SetContainedItemPositions()
|
||||
{
|
||||
Vector2 simPos = item.SimPosition;
|
||||
Vector2 displayPos = item.Position;
|
||||
Vector2 transformedItemPos = ItemPos * item.Scale;
|
||||
Vector2 transformedItemInterval = ItemInterval * item.Scale;
|
||||
Vector2 transformedItemIntervalHorizontal = new Vector2(transformedItemInterval.X, 0.0f);
|
||||
Vector2 transformedItemIntervalVertical = new Vector2(0.0f, transformedItemInterval.Y);
|
||||
if (item.body == null)
|
||||
{
|
||||
if (item.FlippedX)
|
||||
{
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
transformedItemPos.X += item.Rect.Width;
|
||||
transformedItemInterval.X = -transformedItemInterval.X;
|
||||
transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
transformedItemPos.Y = -transformedItemPos.Y;
|
||||
transformedItemPos.Y -= item.Rect.Height;
|
||||
transformedItemInterval.Y = -transformedItemInterval.Y;
|
||||
transformedItemIntervalVertical.Y = -transformedItemIntervalVertical.Y;
|
||||
}
|
||||
transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
|
||||
if (Math.Abs(item.Rotation) > 0.01f)
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(MathHelper.ToRadians(-item.Rotation));
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
transformedItemIntervalVertical = Vector2.Transform(transformedItemIntervalVertical, transform);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
if (item.body.Dir == -1.0f)
|
||||
{
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
transformedItemInterval.X = -transformedItemInterval.X;
|
||||
transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
|
||||
}
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
transformedItemPos += item.Position;
|
||||
}
|
||||
|
||||
float currentRotation = itemRotation;
|
||||
if (item.body != null)
|
||||
{
|
||||
currentRotation += item.body.Rotation;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
Vector2 currentItemPos = transformedItemPos;
|
||||
foreach (Item contained in Inventory.AllItems)
|
||||
{
|
||||
if (contained.body != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Vector2 simPos = ConvertUnits.ToSimUnits(currentItemPos);
|
||||
contained.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, currentRotation);
|
||||
contained.body.SetPrevTransform(contained.body.SimPosition, contained.body.Rotation);
|
||||
contained.body.UpdateDrawPosition();
|
||||
@@ -365,14 +433,29 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
contained.Rect =
|
||||
new Rectangle(
|
||||
(int)(displayPos.X - contained.Rect.Width / 2.0f),
|
||||
(int)(displayPos.Y + contained.Rect.Height / 2.0f),
|
||||
(int)(currentItemPos.X - contained.Rect.Width / 2.0f),
|
||||
(int)(currentItemPos.Y + contained.Rect.Height / 2.0f),
|
||||
contained.Rect.Width, contained.Rect.Height);
|
||||
|
||||
contained.Submarine = item.Submarine;
|
||||
contained.CurrentHull = item.CurrentHull;
|
||||
|
||||
contained.SetContainedItemPositions();
|
||||
|
||||
i++;
|
||||
if (Math.Abs(ItemInterval.X) > 0.001f && Math.Abs(ItemInterval.Y) > 0.001f)
|
||||
{
|
||||
//interval set on both axes -> use a grid layout
|
||||
currentItemPos += transformedItemIntervalHorizontal;
|
||||
if (i % ItemsPerRow == 0)
|
||||
{
|
||||
currentItemPos = transformedItemPos;
|
||||
currentItemPos += transformedItemIntervalVertical * (i / ItemsPerRow);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentItemPos += transformedItemInterval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +493,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void SpawnAlwaysContainedItems()
|
||||
{
|
||||
if (SpawnWithId.Length > 0)
|
||||
if (SpawnWithId.Length > 0 && (item.Condition > 0.0f || SpawnWithIdWhenBroken))
|
||||
{
|
||||
string[] splitIds = SpawnWithId.Split(',');
|
||||
foreach (string id in splitIds)
|
||||
|
||||
@@ -102,6 +102,12 @@ namespace Barotrauma.Items.Components
|
||||
get { return limbPositions.Count > 0; }
|
||||
}
|
||||
|
||||
public bool UserInCorrectPosition
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool AllowAiming
|
||||
{
|
||||
get;
|
||||
@@ -149,6 +155,7 @@ namespace Barotrauma.Items.Components
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
this.cam = cam;
|
||||
UserInCorrectPosition = false;
|
||||
|
||||
if (IsToggle)
|
||||
{
|
||||
@@ -189,6 +196,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
user.AnimController.TargetMovement = Vector2.Zero;
|
||||
UserInCorrectPosition = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -197,7 +205,7 @@ namespace Barotrauma.Items.Components
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && user != Character.Controlled)
|
||||
{
|
||||
if (Math.Abs(diff.X) > 20.0f)
|
||||
{
|
||||
{
|
||||
//wait for the character to walk to the correct position
|
||||
return;
|
||||
}
|
||||
@@ -218,7 +226,8 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
}
|
||||
user.AnimController.TargetMovement = Vector2.Zero;
|
||||
user.AnimController.TargetMovement = Vector2.Zero;
|
||||
UserInCorrectPosition = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,7 +374,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
for (int i = item.LastSentSignalRecipients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (item.LastSentSignalRecipients[i].Item.Condition <= 0.0f) { continue; }
|
||||
if (item.LastSentSignalRecipients[i].Item.Condition <= 0.0f || item.LastSentSignalRecipients[i].IsPower) { continue; }
|
||||
if (item.LastSentSignalRecipients[i].Item.Prefab.FocusOnSelected)
|
||||
{
|
||||
return item.LastSentSignalRecipients[i].Item;
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace Barotrauma.Items.Components
|
||||
private void StartFabricating(FabricationRecipe selectedItem, Character user, bool addToServerLog = true)
|
||||
{
|
||||
if (selectedItem == null) { return; }
|
||||
if (!outputContainer.Inventory.CanBePut(selectedItem.TargetItem)) { return; }
|
||||
if (!outputContainer.Inventory.CanBePut(selectedItem.TargetItem, selectedItem.OutCondition)) { return; }
|
||||
|
||||
#if CLIENT
|
||||
itemList.Enabled = false;
|
||||
@@ -308,7 +308,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
Character tempUser = user;
|
||||
int amountFittingContainer = outputContainer.Inventory.HowManyCanBePut(fabricatedItem.TargetItem);
|
||||
int amountFittingContainer = outputContainer.Inventory.HowManyCanBePut(fabricatedItem.TargetItem, fabricatedItem.OutCondition);
|
||||
for (int i = 0; i < fabricatedItem.Amount; i++)
|
||||
{
|
||||
if (i < amountFittingContainer)
|
||||
@@ -334,7 +334,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (user != null && !user.Removed)
|
||||
if (user?.Info != null && !user.Removed)
|
||||
{
|
||||
foreach (Skill skill in fabricatedItem.RequiredSkills)
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Barotrauma.Items.Components
|
||||
set { maxFlow = value; }
|
||||
}
|
||||
|
||||
[Editable, Serialize(true, false, alwaysUseInstanceValues: true)]
|
||||
[Editable, Serialize(true, true, alwaysUseInstanceValues: true)]
|
||||
public bool IsOn
|
||||
{
|
||||
get { return IsActive; }
|
||||
|
||||
@@ -234,7 +234,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//use a smoothed "correct output" instead of the actual correct output based on the load
|
||||
//so the player doesn't have to keep adjusting the rate impossibly fast when the load fluctuates heavily
|
||||
correctTurbineOutput += MathHelper.Clamp((load / MaxPowerOutput * 100.0f) - correctTurbineOutput, -10.0f, 10.0f) * deltaTime;
|
||||
if (!MathUtils.NearlyEqual(MaxPowerOutput, 0.0f))
|
||||
{
|
||||
correctTurbineOutput += MathHelper.Clamp((load / MaxPowerOutput * 100.0f) - correctTurbineOutput, -10.0f, 10.0f) * deltaTime;
|
||||
}
|
||||
|
||||
//calculate tolerances of the meters based on the skills of the user
|
||||
//more skilled characters have larger "sweet spots", making it easier to keep the power output at a suitable level
|
||||
@@ -320,7 +323,7 @@ namespace Barotrauma.Items.Components
|
||||
//reset the fission rate, turbine output and
|
||||
//temperature to optimal levels to prevent fires
|
||||
//at the start of the round
|
||||
correctTurbineOutput = currentLoad / MaxPowerOutput * 100.0f;
|
||||
correctTurbineOutput = MathUtils.NearlyEqual(MaxPowerOutput, 0.0f) ? 0.0f : currentLoad / MaxPowerOutput * 100.0f;
|
||||
tolerance = MathHelper.Lerp(2.5f, 10.0f, degreeOfSuccess);
|
||||
optimalTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
||||
|
||||
@@ -795,6 +795,7 @@ namespace Barotrauma.Items.Components
|
||||
steeringInput = XMLExtensions.ParseVector2(signal.value, errorMessages: false);
|
||||
steeringInput.X = MathHelper.Clamp(steeringInput.X, -100.0f, 100.0f);
|
||||
steeringInput.Y = MathHelper.Clamp(-steeringInput.Y, -100.0f, 100.0f);
|
||||
TargetVelocity = steeringInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -74,8 +74,6 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(100f, true, "How much fertilizer can the planter hold.")]
|
||||
public float FertilizerCapacity { get; set; }
|
||||
|
||||
public string LastAction { get; set; } = "";
|
||||
|
||||
public Growable?[] GrowableSeeds = new Growable?[0];
|
||||
|
||||
private readonly List<RelatedItem> SuitableFertilizer = new List<RelatedItem>();
|
||||
@@ -119,7 +117,7 @@ namespace Barotrauma.Items.Components
|
||||
GrowableSeeds = new Growable[container.Capacity];
|
||||
}
|
||||
|
||||
public override bool HasRequiredItems(Character character, bool addMessage, string msg = null)
|
||||
public override bool HasRequiredItems(Character character, bool addMessage, string? msg = null)
|
||||
{
|
||||
if (container?.Inventory == null) { return false; }
|
||||
|
||||
@@ -137,9 +135,16 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
Msg = MsgHarvest;
|
||||
if (GrowableSeeds.Any(s => s != null))
|
||||
{
|
||||
Msg = MsgHarvest;
|
||||
ParseMsg();
|
||||
return true;
|
||||
}
|
||||
|
||||
Msg = string.Empty;
|
||||
ParseMsg();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Pick(Character character)
|
||||
@@ -163,9 +168,16 @@ namespace Barotrauma.Items.Components
|
||||
switch (plantItem.Type)
|
||||
{
|
||||
case PlantItemType.Seed:
|
||||
LastAction = "PlantSeed";
|
||||
ApplyStatusEffects(ActionType.OnPicked, 1.0f, character);
|
||||
return container.Inventory.TryPutItem(plantItem.Item, character, new List<InvSlotType> { InvSlotType.Any });
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
return container.Inventory.TryPutItem(plantItem.Item, character);
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the server handle moving the item
|
||||
return false;
|
||||
}
|
||||
case PlantItemType.Fertilizer when plantItem.Item != null:
|
||||
float canAdd = FertilizerCapacity - Fertilizer;
|
||||
float maxAvailable = plantItem.Item.Condition;
|
||||
@@ -175,7 +187,6 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
character.UpdateHUDProgressBar(this, Item.DrawPosition, Fertilizer / FertilizerCapacity, Color.SaddleBrown, Color.SaddleBrown, "entityname.fertilizer");
|
||||
#endif
|
||||
LastAction = "ApplyFertilizer";
|
||||
ApplyStatusEffects(ActionType.OnPicked, 1.0f, character);
|
||||
return false;
|
||||
}
|
||||
@@ -203,7 +214,6 @@ namespace Barotrauma.Items.Components
|
||||
container?.Inventory.RemoveItem(seed.Item);
|
||||
Entity.Spawner?.AddToRemoveQueue(seed.Item);
|
||||
GrowableSeeds[i] = null;
|
||||
LastAction = "Harvest";
|
||||
ApplyStatusEffects(ActionType.OnPicked, 1.0f, character);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (item.Connections == null)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isRunning = true;
|
||||
float chargeRatio = charge / capacity;
|
||||
float gridPower = 0.0f;
|
||||
@@ -173,7 +179,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
currPowerConsumption = MathHelper.Lerp(currPowerConsumption, rechargeSpeed, 0.05f);
|
||||
float missingCharge = capacity - charge;
|
||||
float targetRechargeSpeed = rechargeSpeed;
|
||||
if (missingCharge < 1.0f)
|
||||
{
|
||||
targetRechargeSpeed *= missingCharge;
|
||||
}
|
||||
currPowerConsumption = MathHelper.Lerp(currPowerConsumption, targetRechargeSpeed, 0.05f);
|
||||
Charge += currPowerConsumption * Math.Min(Voltage, 1.0f) / 3600.0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -408,21 +408,25 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
bool hitSomething = false;
|
||||
int hitCount = 0;
|
||||
Vector2 lastHitPos = item.WorldPosition;
|
||||
hits = hits.OrderBy(h => h.Fraction).ToList();
|
||||
foreach (HitscanResult h in hits)
|
||||
for (int i = 0; i < hits.Count; i++)
|
||||
{
|
||||
var h = hits[i];
|
||||
item.SetTransform(h.Point, rotation);
|
||||
if (HandleProjectileCollision(h.Fixture, h.Normal, Vector2.Zero))
|
||||
{
|
||||
LaunchProjSpecific(rayStartWorld, item.WorldPosition);
|
||||
hitSomething = true;
|
||||
break;
|
||||
hitCount++;
|
||||
if (hitCount >= MaxTargetsToHit || i == hits.Count - 1)
|
||||
{
|
||||
LaunchProjSpecific(rayStartWorld, item.WorldPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//the raycast didn't hit anything -> the projectile flew somewhere outside the level and is permanently lost
|
||||
if (!hitSomething)
|
||||
//the raycast didn't hit anything (or didn't hit enough targets to stop the projectile) -> the projectile flew somewhere outside the level and is permanently lost
|
||||
if (hitCount < MaxTargetsToHit)
|
||||
{
|
||||
item.body.SetTransformIgnoreContacts(item.body.SimPosition, rotation);
|
||||
LaunchProjSpecific(rayStartWorld, rayEndWorld);
|
||||
@@ -467,7 +471,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
if (fixture.Body.UserData is VineTile) { return true; }
|
||||
if (fixture.Body.UserData is Item item && (item.GetComponent<Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0)) { return true; }
|
||||
if (fixture.Body.UserData as string == "ruinroom") { return true; }
|
||||
if (fixture.Body.UserData as string == "ruinroom" || fixture.Body.UserData is Hull || fixture.UserData is Hull) { return true; }
|
||||
|
||||
//if doing the raycast in a submarine's coordinate space, ignore anything that's not in that sub
|
||||
if (submarine != null)
|
||||
@@ -505,7 +509,7 @@ namespace Barotrauma.Items.Components
|
||||
if (fixture.Body.UserData is VineTile) { return -1; }
|
||||
|
||||
if (fixture.Body.UserData is Item item && (item.GetComponent<Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0)) { return -1; }
|
||||
if (fixture.Body?.UserData as string == "ruinroom") { return -1; }
|
||||
if (fixture.Body.UserData as string == "ruinroom" || fixture.Body?.UserData is Hull || fixture.UserData is Hull) { return -1; }
|
||||
|
||||
//ignore everything else than characters, sub walls and level walls
|
||||
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
|
||||
@@ -640,7 +644,7 @@ namespace Barotrauma.Items.Components
|
||||
item.body.SimPosition - ConvertUnits.ToSimUnits(sub.Position) - dir,
|
||||
item.body.SimPosition - ConvertUnits.ToSimUnits(sub.Position) + dir,
|
||||
collisionCategory: Physics.CollisionWall);
|
||||
if (wallBody?.FixtureList?.First() != null && wallBody.UserData is Structure &&
|
||||
if (wallBody?.FixtureList?.First() != null && (wallBody.UserData is Structure || wallBody.UserData is Item) &&
|
||||
//ignore the hit if it's behind the position the item was launched from, and the projectile is travelling in the opposite direction
|
||||
Vector2.Dot(item.body.SimPosition - launchPos, dir) > 0)
|
||||
{
|
||||
@@ -738,7 +742,15 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (target.Body.UserData is IDamageable damageable)
|
||||
{
|
||||
if (Attack != null) { attackResult = Attack.DoDamage(User ?? Attacker, damageable, item.WorldPosition, 1.0f); }
|
||||
if (Attack != null)
|
||||
{
|
||||
Vector2 pos = item.WorldPosition;
|
||||
if (item.Submarine == null && damageable is Structure structure && structure.Submarine != null && Vector2.DistanceSquared(item.WorldPosition, structure.WorldPosition) > 10000.0f * 10000.0f)
|
||||
{
|
||||
item.Submarine = structure.Submarine;
|
||||
}
|
||||
attackResult = Attack.DoDamage(User ?? Attacker, damageable, pos, 1.0f);
|
||||
}
|
||||
}
|
||||
else if (target.Body.UserData is VoronoiCell voronoiCell && voronoiCell.IsDestructible && Attack != null && Math.Abs(Attack.LevelWallDamage) > 0.0f)
|
||||
{
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Barotrauma.Items.Components
|
||||
//backwards compatibility
|
||||
var repairThresholdAttribute =
|
||||
element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals("showrepairuithreshold", StringComparison.OrdinalIgnoreCase)) ??
|
||||
element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals("airepairth44reshold", StringComparison.OrdinalIgnoreCase));
|
||||
element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals("airepairthreshold", StringComparison.OrdinalIgnoreCase));
|
||||
if (repairThresholdAttribute != null)
|
||||
{
|
||||
if (float.TryParse(repairThresholdAttribute.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out float repairThreshold))
|
||||
@@ -349,7 +349,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Skill skill in requiredSkills)
|
||||
{
|
||||
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
|
||||
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
|
||||
CurrentFixer.Info?.IncreaseSkillLevel(skill.Identifier,
|
||||
SkillSettings.Current.SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f),
|
||||
CurrentFixer.Position + Vector2.UnitY * 100.0f);
|
||||
}
|
||||
@@ -379,7 +379,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Skill skill in requiredSkills)
|
||||
{
|
||||
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
|
||||
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
|
||||
CurrentFixer.Info?.IncreaseSkillLevel(skill.Identifier,
|
||||
SkillSettings.Current.SkillIncreasePerSabotage / Math.Max(characterSkillLevel, 1.0f),
|
||||
CurrentFixer.Position + Vector2.UnitY * 100.0f);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -23,7 +24,7 @@ namespace Barotrauma.Items.Components
|
||||
private int signalQueueSize;
|
||||
private int delayTicks;
|
||||
|
||||
private Queue<DelayedSignal> signalQueue;
|
||||
private readonly Queue<DelayedSignal> signalQueue;
|
||||
|
||||
private DelayedSignal prevQueuedSignal;
|
||||
|
||||
@@ -37,7 +38,7 @@ namespace Barotrauma.Items.Components
|
||||
if (value == delay) { return; }
|
||||
delay = value;
|
||||
delayTicks = (int)(delay / Timing.Step);
|
||||
signalQueueSize = delayTicks * 2;
|
||||
signalQueueSize = Math.Max(delayTicks, 1) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +75,14 @@ namespace Barotrauma.Items.Components
|
||||
var signalOut = signalQueue.Peek();
|
||||
signalOut.SendDuration -= 1;
|
||||
item.SendSignal(new Signal(signalOut.Signal.value, strength: signalOut.Signal.strength), "signal_out");
|
||||
if (signalOut.SendDuration <= 0) { signalQueue.Dequeue(); } else { break; }
|
||||
if (signalOut.SendDuration <= 0)
|
||||
{
|
||||
signalQueue.Dequeue();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Barotrauma.Items.Components
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static bool operator==(Signal a, Signal b) =>
|
||||
public static bool operator ==(Signal a, Signal b) =>
|
||||
a.value == b.value &&
|
||||
a.stepsTaken == b.stepsTaken &&
|
||||
a.sender == b.sender &&
|
||||
@@ -35,6 +35,6 @@ namespace Barotrauma.Items.Components
|
||||
MathUtils.NearlyEqual(a.power, b.power) &&
|
||||
MathUtils.NearlyEqual(a.strength, b.strength);
|
||||
|
||||
public static bool operator!=(Signal a, Signal b) => !(a == b);
|
||||
public static bool operator !=(Signal a, Signal b) => !(a == b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,11 +77,10 @@ namespace Barotrauma.Items.Components
|
||||
//item in water -> we definitely want to send the True output
|
||||
isInWater = true;
|
||||
}
|
||||
else if (item.CurrentHull != null)
|
||||
else if (item.CurrentHull != null && item.CurrentHull.WaterPercentage > 0.0f)
|
||||
{
|
||||
//item in not water -> check if there's water anywhere within the rect of the item
|
||||
if (item.CurrentHull.Surface > item.CurrentHull.Rect.Y - item.CurrentHull.Rect.Height + 1 &&
|
||||
item.CurrentHull.Surface > item.Rect.Y - item.Rect.Height)
|
||||
//(center of the) item in not water -> check if the water surface is below the bottom of the item's rect
|
||||
if (item.CurrentHull.Surface > item.Rect.Y - item.Rect.Height)
|
||||
{
|
||||
isInWater = true;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private string prevSignal;
|
||||
|
||||
private int[] channelMemory = new int[ChannelMemorySize];
|
||||
private readonly int[] channelMemory = new int[ChannelMemorySize];
|
||||
|
||||
private Connection signalOutConnection;
|
||||
|
||||
[Serialize(CharacterTeamType.None, true, description: "WiFi components can only communicate with components that have the same Team ID.", alwaysUseInstanceValues: true)]
|
||||
public CharacterTeamType TeamID { get; set; }
|
||||
@@ -93,6 +95,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
if (item.Connections != null)
|
||||
{
|
||||
signalOutConnection = item.Connections.Find(c => c.Name == "signal_out");
|
||||
}
|
||||
if (channelMemory.All(m => m == 0))
|
||||
{
|
||||
for (int i = 0; i < channelMemory.Length; i++)
|
||||
@@ -155,6 +161,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void TransmitSignal(Signal signal, bool sentFromChat)
|
||||
{
|
||||
if (sentFromChat)
|
||||
{
|
||||
item.LastSentSignalRecipients.Clear();
|
||||
}
|
||||
var senderComponent = signal.source?.GetComponent<WifiComponent>();
|
||||
if (senderComponent != null && !CanReceive(senderComponent)) { return; }
|
||||
|
||||
@@ -168,10 +178,14 @@ namespace Barotrauma.Items.Components
|
||||
//signal strength diminishes by distance
|
||||
float sentSignalStrength = signal.strength *
|
||||
MathHelper.Clamp(1.0f - (Vector2.Distance(item.WorldPosition, wifiComp.item.WorldPosition) / wifiComp.range), 0.0f, 1.0f);
|
||||
Signal s = new Signal(signal.value, signal.stepsTaken, sender: signal.sender, source: signal.source,
|
||||
Signal s = new Signal(signal.value, ++signal.stepsTaken, sender: signal.sender, source: signal.source,
|
||||
power: 0.0f, strength: sentSignalStrength);
|
||||
wifiComp.item.SendSignal(s, "signal_out");
|
||||
|
||||
|
||||
if (wifiComp.signalOutConnection != null)
|
||||
{
|
||||
wifiComp.item.SendSignal(s, wifiComp.signalOutConnection);
|
||||
}
|
||||
|
||||
if (signal.source != null)
|
||||
{
|
||||
foreach (Connection receiver in wifiComp.item.LastSentSignalRecipients)
|
||||
|
||||
@@ -844,10 +844,11 @@ namespace Barotrauma.Items.Components
|
||||
ClearConnections();
|
||||
base.RemoveComponentSpecific();
|
||||
#if CLIENT
|
||||
if (DraggingWire == this) { draggingWire = null; }
|
||||
overrideSprite?.Remove();
|
||||
overrideSprite = null;
|
||||
wireSprite = null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,6 +562,7 @@ namespace Barotrauma.Items.Components
|
||||
//use linked projectile containers in case they have to react to the turret being launched somehow
|
||||
//(play a sound, spawn more projectiles)
|
||||
if (!(e is Item linkedItem)) { continue; }
|
||||
if (!item.prefab.IsLinkAllowed(e.prefab)) { continue; }
|
||||
if (linkedItem.Condition <= 0.0f)
|
||||
{
|
||||
loaderBroken = true;
|
||||
@@ -971,6 +972,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
if (!item.IsInteractable(character)) { continue; }
|
||||
if (!item.prefab.IsLinkAllowed(e.prefab)) { continue; }
|
||||
if (e is Item projectileContainer)
|
||||
{
|
||||
var container = projectileContainer.GetComponent<ItemContainer>();
|
||||
@@ -1323,6 +1325,7 @@ namespace Barotrauma.Items.Components
|
||||
CheckProjectileContainer(item, projectiles, out bool _);
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
if (!item.prefab.IsLinkAllowed(e.prefab)) { continue; }
|
||||
if (e is Item projectileContainer)
|
||||
{
|
||||
CheckProjectileContainer(projectileContainer, projectiles, out bool stopSearching);
|
||||
|
||||
@@ -28,22 +28,25 @@ namespace Barotrauma
|
||||
get { return items.Count; }
|
||||
}
|
||||
|
||||
public bool CanBePut(Item item)
|
||||
public bool CanBePut(Item item, bool ignoreCondition = false)
|
||||
{
|
||||
if (item == null) { return false; }
|
||||
if (items.Count > 0)
|
||||
{
|
||||
if (item.IsFullCondition)
|
||||
if (!ignoreCondition)
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
||||
}
|
||||
else if (MathUtils.NearlyEqual(item.Condition, 0.0f))
|
||||
{
|
||||
if (items.Any(it => !MathUtils.NearlyEqual(it.Condition, 0.0f))) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
if (item.IsFullCondition)
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
||||
}
|
||||
else if (MathUtils.NearlyEqual(item.Condition, 0.0f))
|
||||
{
|
||||
if (items.Any(it => !MathUtils.NearlyEqual(it.Condition, 0.0f))) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (items[0].Prefab.Identifier != item.Prefab.Identifier ||
|
||||
items.Count + 1 > item.Prefab.MaxStackSize)
|
||||
@@ -54,12 +57,31 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanBePut(ItemPrefab itemPrefab)
|
||||
public bool CanBePut(ItemPrefab itemPrefab, float? condition = null)
|
||||
{
|
||||
if (itemPrefab == null) { return false; }
|
||||
if (items.Count > 0)
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
||||
if (condition.HasValue)
|
||||
{
|
||||
if (MathUtils.NearlyEqual(condition.Value, 0.0f))
|
||||
{
|
||||
if (items.Any(it => it.Condition > 0.0f)) { return false; }
|
||||
}
|
||||
else if (MathUtils.NearlyEqual(condition.Value, itemPrefab.Health))
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
||||
}
|
||||
|
||||
if (items[0].Prefab.Identifier != itemPrefab.Identifier ||
|
||||
items.Count + 1 > itemPrefab.MaxStackSize)
|
||||
{
|
||||
@@ -70,13 +92,31 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
/// <param name="maxStackSize">Defaults to <see cref="ItemPrefab.MaxStackSize"/> if null</param>
|
||||
public int HowManyCanBePut(ItemPrefab itemPrefab, int? maxStackSize = null)
|
||||
public int HowManyCanBePut(ItemPrefab itemPrefab, int? maxStackSize = null, float? condition = null)
|
||||
{
|
||||
if (itemPrefab == null) { return 0; }
|
||||
maxStackSize ??= itemPrefab.MaxStackSize;
|
||||
if (items.Count > 0)
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return 0; }
|
||||
if (condition.HasValue)
|
||||
{
|
||||
if (MathUtils.NearlyEqual(condition.Value, 0.0f))
|
||||
{
|
||||
if (items.Any(it => it.Condition > 0.0f)) { return 0; }
|
||||
}
|
||||
else if (MathUtils.NearlyEqual(condition.Value, itemPrefab.Health))
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return 0; }
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (items.Any(it => !it.IsFullCondition)) { return 0; }
|
||||
}
|
||||
if (items[0].Prefab.Identifier != itemPrefab.Identifier) { return 0; }
|
||||
return maxStackSize.Value - items.Count;
|
||||
}
|
||||
@@ -373,42 +413,42 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Can the item be put in the specified slot.
|
||||
/// </summary>
|
||||
public virtual bool CanBePut(Item item, int i)
|
||||
public virtual bool CanBePut(Item item, int i, bool ignoreCondition = false)
|
||||
{
|
||||
if (ItemOwnsSelf(item)) { return false; }
|
||||
if (i < 0 || i >= slots.Length) { return false; }
|
||||
return slots[i].CanBePut(item);
|
||||
return slots[i].CanBePut(item, ignoreCondition);
|
||||
}
|
||||
|
||||
public bool CanBePut(ItemPrefab itemPrefab)
|
||||
public bool CanBePut(ItemPrefab itemPrefab, float? condition = null)
|
||||
{
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (CanBePut(itemPrefab, i)) { return true; }
|
||||
if (CanBePut(itemPrefab, i, condition)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool CanBePut(ItemPrefab itemPrefab, int i)
|
||||
public virtual bool CanBePut(ItemPrefab itemPrefab, int i, float? condition = null)
|
||||
{
|
||||
if (i < 0 || i >= slots.Length) { return false; }
|
||||
return slots[i].CanBePut(itemPrefab);
|
||||
return slots[i].CanBePut(itemPrefab, condition);
|
||||
}
|
||||
|
||||
public int HowManyCanBePut(ItemPrefab itemPrefab)
|
||||
public int HowManyCanBePut(ItemPrefab itemPrefab, float? condition = null)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
count += HowManyCanBePut(itemPrefab, i);
|
||||
count += HowManyCanBePut(itemPrefab, i, condition);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public virtual int HowManyCanBePut(ItemPrefab itemPrefab, int i)
|
||||
public virtual int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition)
|
||||
{
|
||||
if (i < 0 || i >= slots.Length) { return 0; }
|
||||
return slots[i].HowManyCanBePut(itemPrefab);
|
||||
return slots[i].HowManyCanBePut(itemPrefab, condition: condition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user