OBT/1.2.0(Spring Update)

Sync with Upstream
This commit is contained in:
NotAlwaysTrue
2026-04-25 13:25:41 +08:00
committed by GitHub
parent 5207b381b7
commit 59bc21973a
421 changed files with 24090 additions and 11391 deletions
@@ -487,7 +487,21 @@ namespace Barotrauma.Items.Components
return 0.0f;
}
public virtual bool ShouldDrawHUD(Character character)
public bool ShouldDrawHUD(Character character)
{
if (Character.Controlled?.SelectedItem != null)
{
Controller controller = item.GetComponent<Controller>();
if (controller != null && controller.User == Character.Controlled && controller.HideAllItemComponentHUDs)
{
return false;
}
}
return ShouldDrawHUDComponentSpecific(character);
}
protected virtual bool ShouldDrawHUDComponentSpecific(Character character)
{
return true;
}
@@ -552,9 +552,9 @@ namespace Barotrauma.Items.Components
if (flippedY) { origin.Y = contained.Item.Sprite.SourceRect.Height - origin.Y; }
float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? contained.Item.Sprite.Depth : ContainedSpriteDepth;
if (i < containedSpriteDepths.Length)
if (targetSlotIndex < containedSpriteDepths.Length)
{
containedSpriteDepth = containedSpriteDepths[i];
containedSpriteDepth = containedSpriteDepths[targetSlotIndex];
}
containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f;
@@ -52,10 +52,12 @@ namespace Barotrauma.Items.Components
partial void SetLightSourceTransformProjSpecific()
{
Vector2 offset = Vector2.Zero;
if (LightOffset != Vector2.Zero)
Vector2 offset = LightOffset * item.Scale;
if (offset != Vector2.Zero)
{
offset = Vector2.Transform(LightOffset, Matrix.CreateRotationZ(item.FlippedY ? -item.RotationRad - MathHelper.Pi : -item.RotationRad)) * item.Scale;
if (item.FlippedX) { offset.X *= -1; }
if (item.FlippedY) { offset.Y *= -1; }
offset = Vector2.Transform(offset, Matrix.CreateRotationZ(-item.RotationRad));
}
if (ParentBody != null)
@@ -101,7 +103,10 @@ namespace Barotrauma.Items.Components
if (Light?.LightSprite == null) { return; }
if ((item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
{
Vector2 offset = Vector2.Transform(LightOffset, Matrix.CreateRotationZ(item.FlippedY ? -item.RotationRad - MathHelper.Pi : -item.RotationRad)) * item.Scale;
Vector2 offset = LightOffset * item.Scale;
if (item.FlippedX) { offset.X *= -1; }
if (item.FlippedY) { offset.Y *= -1; }
offset = Vector2.Transform(offset, Matrix.CreateRotationZ(-item.RotationRad));
Vector2 origin = Light.LightSprite.Origin;
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
@@ -114,6 +119,7 @@ namespace Barotrauma.Items.Components
{
color = new Color(lightColor, Light.OverrideLightSpriteAlpha.Value);
}
Light.LightSprite.Draw(spriteBatch,
new Vector2(drawPos.X, -drawPos.Y),
color * lightBrightness,
@@ -128,8 +134,16 @@ namespace Barotrauma.Items.Components
{
if (Light?.LightSprite != null && item.Prefab.CanSpriteFlipX)
{
Light.LightSpriteEffect = Light.LightSpriteEffect == SpriteEffects.None ?
SpriteEffects.FlipHorizontally : SpriteEffects.None;
Light.LightSpriteEffect ^= SpriteEffects.FlipHorizontally;
}
SetLightSourceTransformProjSpecific();
}
public override void FlipY(bool relativeToSub)
{
if (Light?.LightSprite != null && item.Prefab.CanSpriteFlipY)
{
Light.LightSpriteEffect ^= SpriteEffects.FlipVertically;
}
SetLightSourceTransformProjSpecific();
}
@@ -8,6 +8,30 @@ namespace Barotrauma.Items.Components
{
private bool isHUDsHidden;
public void UpdateMsg()
{
if (Character.Controlled == null) { return; }
if (!string.IsNullOrEmpty(KickOutCharacterMsg) &&
SelectingKicksCharacterOut &&
User != null && !User.Removed)
{
DisplayMsg = TextManager.ParseInputTypes(TextManager.Get(KickOutCharacterMsg));
}
else if (!string.IsNullOrEmpty(PutOtherCharacterMsg) &&
AllowPuttingInOtherCharacters &&
CanPutSelectedCharacter(Character.Controlled.SelectedCharacter))
{
DisplayMsg = TextManager.ParseInputTypes(TextManager.Get(PutOtherCharacterMsg));
}
else
{
DisplayMsg = TextManager.ParseInputTypes(TextManager.Get(Msg));
}
CharacterHUD.RecreateHudTextsIfControlling(Character.Controlled);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
base.DrawHUD(spriteBatch, character);
@@ -69,21 +93,33 @@ namespace Barotrauma.Items.Components
ushort userID = msg.ReadUInt16();
if (userID == 0)
{
if (user != null)
if (User != null)
{
IsActive = false;
CancelUsing(user);
user = null;
CancelUsing(User);
User = null;
}
}
else
{
Character newUser = Entity.FindEntityByID(userID) as Character;
if (newUser != user)
if (newUser != User)
{
CancelUsing(user);
CancelUsing(User);
}
user = newUser;
User = newUser;
// If the server assigned a user to this controller but the character is not selecting the item
// on the client-side, force the selection to prevent desync. This is required for force attaching,
// since the character placed into the controller may be unconscious, and in that state
// the server no longer syncs the current SelectedItem to clients.
if (ForceUserToStayAttached &&
user != null &&
!user.IsAnySelectedItem(Item))
{
user.SelectedItem = Item;
}
IsActive = true;
}
}
@@ -434,18 +434,13 @@ namespace Barotrauma.Items.Components
foreach (FabricationRecipe fi in fabricationRecipes.Values)
{
RichString recipeTooltip =
fi.RequiresRecipe ?
RichString.Rich(fi.TargetItem.Description + "\n\n" + $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{TextManager.Get("fabricatorrequiresrecipe")}‖color:end‖") :
RichString.Rich(fi.TargetItem.Description);
var frame = new GUIFrame(new RectTransform(new Point(itemList.Content.Rect.Width, (int)(40 * GUI.yScale)), itemList.Content.RectTransform), style: null)
{
UserData = fi,
HoverColor = Color.Gold * 0.2f,
SelectedColor = Color.Gold * 0.5f,
ToolTip = recipeTooltip
};
SetRecipeTooltip(frame, fi);
var container = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform),
childAnchor: Anchor.CenterLeft, isHorizontal: true) { RelativeSpacing = 0.02f };
@@ -457,7 +452,7 @@ namespace Barotrauma.Items.Components
itemIcon, scaleToFit: true)
{
Color = itemIcon == fi.TargetItem.Sprite ? fi.TargetItem.SpriteColor : fi.TargetItem.InventoryIconColor,
ToolTip = recipeTooltip
CanBeFocused = false
};
}
@@ -466,7 +461,7 @@ namespace Barotrauma.Items.Components
{
Padding = Vector4.Zero,
AutoScaleVertical = true,
ToolTip = recipeTooltip
CanBeFocused = false
};
new GUITextBlock(new RectTransform(new Vector2(0.85f, 1f), frame.RectTransform, Anchor.BottomRight),
@@ -478,6 +473,20 @@ namespace Barotrauma.Items.Components
}
}
private void SetRecipeTooltip(GUIComponent component, FabricationRecipe recipe)
{
if (!recipe.RequiresRecipe)
{
component.ToolTip = RichString.Rich(recipe.TargetItem.Description);
}
else
{
component.ToolTip = AnyOneHasRecipeForItem(Character.Controlled, recipe.TargetItem) ?
RichString.Rich(recipe.TargetItem.Description + "\n\n" + $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Green)}‖{TextManager.Get("unlockedrecipe.true")}‖color:end‖") :
RichString.Rich(recipe.TargetItem.Description + "\n\n" + $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{TextManager.Get("fabricatorrequiresrecipe")}‖color:end‖");
}
}
private void InitInventoryUIs()
{
if (inputInventoryHolder != null)
@@ -927,16 +936,24 @@ namespace Barotrauma.Items.Components
}
}
if (recipe.RequiresRecipe && recipe.HideIfNoRecipe)
if (recipe.RequiresRecipe)
{
if (Character.Controlled != null)
if (recipe.HideIfNoRecipe)
{
if (!AnyOneHasRecipeForItem(Character.Controlled, recipe.TargetItem))
bool anyOneHasRecipe = AnyOneHasRecipeForItem(Character.Controlled, recipe.TargetItem);
if (Character.Controlled != null)
{
child.Visible = false;
continue;
if (!anyOneHasRecipe)
{
child.Visible = false;
continue;
}
}
}
else
{
SetRecipeTooltip(child, recipe);
}
}
child.Visible =
@@ -1147,7 +1164,16 @@ namespace Barotrauma.Items.Components
var lines = description.WrappedText.Split('\n');
if (lines.Count <= 1) { break; }
string newString = string.Join('\n', lines.Take(lines.Count - 1));
description.Text = newString.Substring(0, newString.Length - 4) + "...";
if (newString.Length > 4)
{
description.Text = newString.Substring(0, newString.Length - 4) + "...";
}
else
{
description.Text = newString + "...";
}
description.CalculateHeightFromText();
description.ToolTip = richDescription;
}
@@ -443,6 +443,7 @@ namespace Barotrauma.Items.Components
var wire = targetItem.GetComponent<Wire>();
if (wire != null && wire.Connections.Any(c => c != null)) { return false; }
if (targetItem.Container is { NonInteractable: true }) { return false; }
if (targetItem.Container?.GetComponent<ItemContainer>() is { DrawInventory: false } or { AllowAccess: false }) { return false; }
if (targetItem.HasTag(Tags.TraitorMissionItem)) { return false; }
@@ -575,6 +575,22 @@ namespace Barotrauma.Items.Components
pos /= c.Resources.Count;
MineralClusters.Add((center: pos, resources: c.Resources));
}
if (GameMain.GameSession != null)
{
foreach (var mission in GameMain.GameSession.Missions)
{
if (mission is MineralMission mineralMission)
{
foreach (var minerals in mineralMission.SpawnedResources)
{
MineralClusters.Add((
center: new Vector2(minerals.Average(m => m.WorldPosition.X), minerals.Average(m => m.WorldPosition.Y)),
resources: minerals));
}
}
}
}
}
else
{
@@ -823,18 +839,20 @@ namespace Barotrauma.Items.Components
if (t.Entity is Character c && !c.IsUnconscious && c.Params.HideInSonar) { continue; }
if (t.SoundRange <= 0.0f || float.IsNaN(t.SoundRange) || float.IsInfinity(t.SoundRange)) { continue; }
float sonarSoundRange = t.SoundRange * t.SoundRangeOnSonarMultiplier;
float distSqr = Vector2.DistanceSquared(t.WorldPosition, transducerCenter);
if (distSqr > t.SoundRange * t.SoundRange * 2) { continue; }
if (distSqr > sonarSoundRange * sonarSoundRange * 2) { continue; }
float dist = (float)Math.Sqrt(distSqr);
if (dist > prevPassivePingRadius * Range && dist <= passivePingRadius * Range && Rand.Int(sonarBlips.Count) < 500)
{
Ping(t.WorldPosition, transducerCenter,
t.SoundRange * DisplayScale, 0, DisplayScale, range,
sonarSoundRange * DisplayScale, 0, DisplayScale, range,
passive: true, pingStrength: 0.5f, needsToBeInSector: t);
if (t.IsWithinSector(transducerCenter))
{
sonarBlips.Add(new SonarBlip(t.WorldPosition, fadeTimer: 1.0f, scale: MathHelper.Clamp(t.SoundRange / 2000, 1.0f, 5.0f)));
sonarBlips.Add(new SonarBlip(t.WorldPosition, fadeTimer: 1.0f, scale: MathHelper.Clamp(sonarSoundRange / 2000, 1.0f, 5.0f)));
}
}
}
@@ -977,7 +995,9 @@ namespace Barotrauma.Items.Components
if (aiTarget.InDetectable) { continue; }
if (aiTarget.SonarLabel.IsNullOrEmpty() || aiTarget.SoundRange <= 0.0f) { continue; }
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange)
float sonarSoundRange = aiTarget.SoundRange * aiTarget.SoundRangeOnSonarMultiplier;
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < sonarSoundRange * sonarSoundRange)
{
DrawMarker(spriteBatch,
aiTarget.SonarLabel.Value,
@@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components
get { return Vector2.Zero; }
}
public override bool ShouldDrawHUD(Character character)
protected override bool ShouldDrawHUDComponentSpecific(Character character)
{
if (item.IsHidden) { return false; }
if (!HasRequiredItems(character, false) || character.SelectedItem != item) { return false; }
@@ -78,7 +78,7 @@ namespace Barotrauma.Items.Components
}
}
public override bool ShouldDrawHUD(Character character)
protected override bool ShouldDrawHUDComponentSpecific(Character character)
=> character == Character.Controlled && (character.SelectedItem == item || character.SelectedSecondaryItem == item);
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
@@ -97,7 +97,7 @@ namespace Barotrauma.Items.Components
MoveConnectedWires(amount);
}
public override bool ShouldDrawHUD(Character character)
protected override bool ShouldDrawHUDComponentSpecific(Character character)
{
return character == Character.Controlled && character == user && (character.SelectedItem == item || character.SelectedSecondaryItem == item);
}
@@ -287,20 +287,24 @@ namespace Barotrauma.Items.Components
texts.Add(target.CustomInteractHUDText);
textColors.Add(GUIStyle.Green);
}
if (!target.IsIncapacitated && target.IsPet)
if (equipper?.FocusedCharacter == target)
{
texts.Add(CharacterHUD.GetCachedHudText("PlayHint", InputType.Use));
textColors.Add(GUIStyle.Green);
}
if (equipper?.FocusedCharacter == target && target.CanBeHealedBy(equipper, checkFriendlyTeam: false))
{
texts.Add(CharacterHUD.GetCachedHudText("HealHint", InputType.Health));
textColors.Add(GUIStyle.Green);
}
if (target.CanBeDraggedBy(Character.Controlled))
{
texts.Add(CharacterHUD.GetCachedHudText("GrabHint", InputType.Grab));
textColors.Add(GUIStyle.Green);
if (!target.IsIncapacitated && target.IsPet &&
target.AIController is EnemyAIController enemyAI && enemyAI.PetBehavior.CanPlayWith(Character.Controlled))
{
texts.Add(CharacterHUD.GetCachedHudText("PlayHint", InputType.Use));
textColors.Add(GUIStyle.Green);
}
if (target.CanBeHealedBy(equipper, checkFriendlyTeam: false))
{
texts.Add(CharacterHUD.GetCachedHudText("HealHint", InputType.Health));
textColors.Add(GUIStyle.Green);
}
if (target.CanBeDraggedBy(Character.Controlled))
{
texts.Add(CharacterHUD.GetCachedHudText("GrabHint", InputType.Grab));
textColors.Add(GUIStyle.Green);
}
}
if (target.IsUnconscious)
@@ -1597,7 +1597,8 @@ namespace Barotrauma
{
if (DraggingSlot == null || (!DraggingSlot.MouseOn()))
{
Sprite sprite = DraggingItems.First().Prefab.InventoryIcon ?? DraggingItems.First().Sprite;
Item firstDraggingItem = DraggingItems.First();
Sprite sprite = firstDraggingItem.OverrideInventorySprite ?? firstDraggingItem.Prefab.InventoryIcon ?? firstDraggingItem.Sprite;
int iconSize = (int)(64 * GUI.Scale);
float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f);
@@ -1854,7 +1855,7 @@ namespace Barotrauma
if (item != null && drawItem)
{
Sprite sprite = item.Prefab.InventoryIcon ?? item.Sprite;
Sprite sprite = item.OverrideInventorySprite ?? item.Prefab.InventoryIcon ?? item.Sprite;
float scale = Math.Min(Math.Min((rect.Width - 10) / sprite.size.X, (rect.Height - 10) / sprite.size.Y), 2.0f);
Vector2 itemPos = rect.Center.ToVector2();
if (itemPos.Y > GameMain.GraphicsHeight)
@@ -419,7 +419,7 @@ namespace Barotrauma
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
float d = MathHelper.Clamp(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.0f, 0.999f);
fadeInBrokenSprite.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
textureScale: Vector2.One * Scale,
depth: d);
@@ -435,7 +435,7 @@ namespace Barotrauma
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, RotationRad, Scale, activeSprite.effects, depth);
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
float d = MathHelper.Clamp(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.0f, 0.999f);
fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, RotationRad, Scale, activeSprite.effects, d);
}
}
@@ -885,7 +885,12 @@ namespace Barotrauma
Spacing = (int)(25 * GUI.Scale)
};
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUIStyle.LargeFont) { UserData = this };
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true,
titleFont: GUIStyle.LargeFont,
dimOutDefaultValues: false)
{
UserData = this
};
activeEditors.Add(itemEditor);
itemEditor.Children.First().Color = Color.Black * 0.7f;
if (!inGame)
@@ -1045,7 +1050,12 @@ namespace Barotrauma
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), listBox.Content.RectTransform), style: "HorizontalLine");
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame, titleFont: GUIStyle.SubHeadingFont) { UserData = ic };
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame,
titleFont: GUIStyle.SubHeadingFont,
dimOutDefaultValues: false)
{
UserData = ic
};
componentEditor.Children.First().Color = Color.Black * 0.7f;
activeEditors.Add(componentEditor);
@@ -1064,7 +1074,12 @@ namespace Barotrauma
requiredItems.Add(relatedItem);
}
}
requiredItems.AddRange(ic.DisabledRequiredItems);
//if we have some actual requirements, no need to keep the empty requirement
//as a "placeholder" for the user to add requirements in the sub editor
if (ic.RequiredItems.None())
{
requiredItems.AddRange(ic.DisabledRequiredItems);
}
foreach (RelatedItem relatedItem in requiredItems)
{
@@ -1626,12 +1641,16 @@ namespace Barotrauma
activeComponents.Clear();
activeComponents.AddRange(components);
foreach (MapEntity entity in linkedTo)
Controller controller = GetComponent<Controller>();
if (controller == null || controller.User != Character.Controlled || !controller.HideAllItemComponentHUDs)
{
if (Prefab.IsLinkAllowed(entity.Prefab) && entity is Item i)
foreach (MapEntity entity in linkedTo)
{
if (!i.DisplaySideBySideWhenLinked) { continue; }
activeComponents.AddRange(i.components);
if (Prefab.IsLinkAllowed(entity.Prefab) && entity is Item i)
{
if (!i.DisplaySideBySideWhenLinked) { continue; }
activeComponents.AddRange(i.components);
}
}
}
@@ -1701,7 +1720,9 @@ namespace Barotrauma
foreach (Character otherCharacter in Character.CharacterList)
{
if (otherCharacter != character &&
otherCharacter.SelectedItem == this)
otherCharacter.SelectedItem == this &&
// Prevent the in use message from being shown if a character is, for example, inside the deconstructor
!otherCharacter.IsAttachedToController())
{
ItemInUseWarning.Visible = true;
if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); }
@@ -1751,6 +1772,11 @@ namespace Barotrauma
}
}
public void ClearActiveHUDs()
{
activeHUDs.Clear();
}
readonly List<ColoredText> texts = new();
public List<ColoredText> GetHUDTexts(Character character, bool recreateHudTexts = true)
{
@@ -166,6 +166,14 @@ namespace Barotrauma
subElement.GetAttributeBool("fadein", false),
subElement.GetAttributePoint("offset", Point.Zero));
if (brokenSprite.FadeIn && brokenSprite.MaxConditionPercentage <= 0.0f)
{
DebugConsole.AddWarning(
$"Potential error in item {Identifier}: a broken sprite that's set to fade in despite the max condition being 0."+
" The sprite cannot fade in if it's set to only appear when the item is fully broken.",
ContentPackage);
}
int spriteIndex = 0;
for (int i = 0; i < brokenSprites.Count && brokenSprites[i].MaxConditionPercentage < brokenSprite.MaxConditionPercentage; i++)
{