Release v0.15.12.0

This commit is contained in:
Joonas Rikkonen
2021-10-27 18:50:57 +03:00
parent bf95e82d80
commit 234fb6bc06
450 changed files with 26042 additions and 10457 deletions
@@ -161,7 +161,7 @@ namespace Barotrauma
public override void CreateSlots()
{
if (visualSlots == null) { visualSlots = new VisualSlot[capacity]; }
visualSlots ??= new VisualSlot[capacity];
float multiplier = !GUI.IsFourByThree() ? UIScale : UIScale * 0.925f;
@@ -174,6 +174,12 @@ namespace Barotrauma
(int)SlotPositions[i].X,
(int)SlotPositions[i].Y,
(int)(slotSprite.size.X * multiplier), (int)(slotSprite.size.Y * multiplier));
if (SlotTypes[i] == InvSlotType.HealthInterface &&
character.CharacterHealth?.InventorySlotContainer != null)
{
slotRect.Width = slotRect.Height = (int)(character.CharacterHealth.InventorySlotContainer.Rect.Width * 1.2f);
}
ItemContainer itemContainer = slots[i].FirstOrDefault()?.GetComponent<ItemContainer>();
if (itemContainer != null)
@@ -238,6 +244,8 @@ namespace Barotrauma
{
if (visualSlots[i].Disabled || (slots[i].HideIfEmpty && slots[i].Empty())) { return true; }
if (CharacterHealth.OpenHealthWindow != Character.Controlled?.CharacterHealth && SlotTypes[i] == InvSlotType.HealthInterface) { return true; }
if (layout == Layout.Default)
{
if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(visualSlots[i].Rect.Center + visualSlots[i].DrawOffset.ToPoint())) { return true; }
@@ -315,7 +323,7 @@ namespace Barotrauma
case Layout.Default:
{
int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s) && s != InvSlotType.HealthInterface);
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
@@ -359,7 +367,8 @@ namespace Barotrauma
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
for (int i = 0; i < visualSlots.Length; i++)
{
if (HideSlot(i)) continue;
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
//upperX -= slotSize.X + spacing;
@@ -371,10 +380,18 @@ namespace Barotrauma
}
int lowerX = x;
int handSlotX = x;
int personalSlotY = GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2 - (int)(!GUI.IsFourByThree() ? UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment : UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment * 2f);
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
{
SlotPositions[i] = new Vector2(handSlotX, personalSlotY);
handSlotX += visualSlots[i].Rect.Width + Spacing;
continue;
}
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
@@ -390,7 +407,8 @@ namespace Barotrauma
x = lowerX;
for (int i = 0; i < SlotPositions.Length; i++)
{
if (!HideSlot(i)) continue;
if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
x -= visualSlots[i].Rect.Width + Spacing;
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
}
@@ -404,7 +422,8 @@ namespace Barotrauma
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
if (PersonalSlots.HasFlag(SlotTypes[i]))
{
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
@@ -416,9 +435,16 @@ namespace Barotrauma
x += visualSlots[i].Rect.Width + Spacing;
}
}
int handSlotX = x - visualSlots[0].Rect.Width - Spacing;
for (int i = 0; i < SlotPositions.Length; i++)
{
if (!HideSlot(i)) continue;
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
{
bool rightSlot = SlotTypes[i] == InvSlotType.RightHand;
SlotPositions[i] = new Vector2(rightSlot ? handSlotX : handSlotX - visualSlots[0].Rect.Width - Spacing, personalSlotY);
continue;
}
if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
x += visualSlots[i].Rect.Width + Spacing;
}
@@ -432,7 +458,7 @@ namespace Barotrauma
int x = startX, y = startY;
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
if (SlotTypes[i] == InvSlotType.Card || SlotTypes[i] == InvSlotType.Headset || SlotTypes[i] == InvSlotType.InnerClothes)
{
SlotPositions[i] = new Vector2(x, y);
@@ -444,7 +470,7 @@ namespace Barotrauma
int n = 0;
for (int i = 0; i < SlotPositions.Length; i++)
{
if (HideSlot(i)) continue;
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
if (SlotTypes[i] != InvSlotType.Card && SlotTypes[i] != InvSlotType.Headset && SlotTypes[i] != InvSlotType.InnerClothes)
{
SlotPositions[i] = new Vector2(x, y);
@@ -461,13 +487,23 @@ namespace Barotrauma
}
break;
}
if (character.CharacterHealth?.UseHealthWindow ?? false)
{
Vector2 pos = character.CharacterHealth.InventorySlotContainer.Rect.Location.ToVector2();
for (int i = 0; i < capacity; i++)
{
if (SlotTypes[i] != InvSlotType.HealthInterface) { continue; }
SlotPositions[i] = pos;
pos.Y += visualSlots[i].Rect.Height + Spacing;
}
}
CreateSlots();
if (layout == Layout.Default)
{
HUDLayoutSettings.InventoryTopY = visualSlots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
}
}
protected override void ControlInput(Camera cam)
@@ -652,6 +688,11 @@ namespace Barotrauma
{
break;
}
//if putting an item to a container with a max stack size of 1, only put one item from the stack
if (quickUseAction == QuickUseAction.PutToContainer && (character.SelectedConstruction?.GetComponent<ItemContainer>()?.MaxStackSize ?? 0) <= 1)
{
break;
}
}
}
@@ -661,7 +702,7 @@ namespace Barotrauma
if (item != null)
{
var slot = visualSlots[i];
if (item.AllowedSlots.Any(a => a != InvSlotType.Any))
if (item.AllowedSlots.Any(a => a != InvSlotType.Any && a != InvSlotType.HealthInterface))
{
HandleButtonEquipStates(item, slot, deltaTime);
}
@@ -840,7 +881,9 @@ namespace Barotrauma
private QuickUseAction GetQuickUseAction(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
{
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null)
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null &&
//if the item can be equipped in the health interface slot, don't use it as a treatment but try to equip it
!item.AllowedSlots.Contains(InvSlotType.HealthInterface))
{
return QuickUseAction.UseTreatment;
}
@@ -1135,7 +1178,7 @@ namespace Barotrauma
for (int i = 0; i < capacity; i++)
{
if (HideSlot(i)) { continue; }
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
//don't draw the item if it's being dragged out of the slot
bool drawItem = !DraggingItems.Any() || !slots[i].Items.All(it => DraggingItems.Contains(it)) || visualSlots[i].MouseOn();
@@ -1189,7 +1232,7 @@ namespace Barotrauma
highlightedQuickUseSlot = visualSlots[i];
}
if (!slots[i].First().AllowedSlots.Any(a => a == InvSlotType.Any))
if (slots[i].First().AllowedSlots.Count() == 1 || SlotTypes[i] == InvSlotType.HealthInterface)
{
continue;
}
@@ -0,0 +1,61 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
internal partial class EntitySpawnerComponent
{
public Vector2 DrawSize => Vector2.Zero;
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (!editing) { return; }
switch (SpawnAreaShape)
{
case AreaShape.Rectangle:
{
RectangleF rect = GetAreaRectangle(SpawnAreaBounds, SpawnAreaOffset, draw: true);
GUI.DrawRectangle(spriteBatch, rect.Location, rect.Size, GUI.Style.Red, isFilled: false, 0f, 4f);
if (MaximumAmountRangePadding > 0f)
{
rect.Inflate(MaximumAmountRangePadding, MaximumAmountRangePadding);
GUI.DrawRectangle(spriteBatch, rect.Location, rect.Size, GUI.Style.Red, isFilled: false, 0f, 2f);
}
break;
}
case AreaShape.Circle:
Vector2 center = item.WorldPosition;
center.Y = -center.Y;
center += SpawnAreaOffset;
spriteBatch.DrawCircle(center, SpawnAreaRadius, 32, GUI.Style.Red, thickness: 4f);
if (MaximumAmountRangePadding > 0f)
{
spriteBatch.DrawCircle(center, SpawnAreaRadius + MaximumAmountRangePadding, 32, GUI.Style.Red, thickness: 2f);
}
break;
}
if (!OnlySpawnWhenCrewInRange) { return; }
switch (CrewAreaShape)
{
case AreaShape.Rectangle:
{
RectangleF rect = GetAreaRectangle(CrewAreaBounds, CrewAreaOffset, draw: true);
GUI.DrawRectangle(spriteBatch, rect.Location, rect.Size, GUI.Style.Green, isFilled: false, 0f, 4f);
break;
}
case AreaShape.Circle:
Vector2 center = item.WorldPosition;
center.Y = -center.Y;
center += CrewAreaOffset;
spriteBatch.DrawCircle(center, CrewAreaRadius, 32, GUI.Style.Green);
break;
}
}
}
}
@@ -0,0 +1,86 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Linq;
namespace Barotrauma.Items.Components
{
partial class GeneticMaterial : ItemComponent
{
[Serialize(0.0f, false)]
public float TooltipValueMin { get; set; }
[Serialize(0.0f, false)]
public float TooltipValueMax { get; set; }
public override void AddTooltipInfo(ref string name, ref string description)
{
if (!string.IsNullOrEmpty(materialName) && item.ContainedItems.Count() > 0)
{
string mergedMaterialName = materialName;
foreach (Item containedItem in item.ContainedItems)
{
var containedMaterial = containedItem.GetComponent<GeneticMaterial>();
if (containedMaterial == null) { continue; }
mergedMaterialName += ", " + containedMaterial.materialName;
}
name = name.Replace(materialName, mergedMaterialName);
}
if (Tainted)
{
name = TextManager.GetWithVariable("entityname.taintedgeneticmaterial", "[geneticmaterialname]", name);
}
if (TextManager.ContainsTag("entitydescription." + Item.prefab.Identifier))
{
int value = (int)MathHelper.Lerp(TooltipValueMin, TooltipValueMax, item.ConditionPercentage / 100.0f);
description = TextManager.GetWithVariable("entitydescription." + Item.prefab.Identifier, "[value]", value.ToString());
}
foreach (Item containedItem in item.ContainedItems)
{
var containedGeneticMaterial = containedItem.GetComponent<GeneticMaterial>();
if (containedGeneticMaterial == null) { continue; }
string _ = string.Empty;
string containedDescription = containedItem.Description;
containedGeneticMaterial.AddTooltipInfo(ref _, ref containedDescription);
if (!string.IsNullOrEmpty(containedDescription))
{
description += '\n' + containedDescription;
}
}
}
public void ModifyDeconstructInfo(Deconstructor deconstructor, ref string buttonText, ref string infoText)
{
if (deconstructor.InputContainer.Inventory.AllItems.Count() == 2)
{
if (!deconstructor.InputContainer.Inventory.AllItems.All(it => it.prefab == item.prefab))
{
buttonText = TextManager.Get("researchstation.combine");
infoText = TextManager.Get("researchstation.combine.infotext");
}
else
{
buttonText = TextManager.Get("researchstation.refine");
int taintedProbability = (int)(GetTaintedProbabilityOnRefine(Character.Controlled) * 100);
infoText = TextManager.GetWithVariable("researchstation.refine.infotext", "[taintedprobability]", taintedProbability.ToString());
}
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
Tainted = msg.ReadBoolean();
if (Tainted)
{
uint selectedTaintedEffectId = msg.ReadUInt32();
selectedTaintedEffect = AfflictionPrefab.Prefabs.Find(a => a.UIntIdentifier == selectedTaintedEffectId);
}
else
{
uint selectedEffectId = msg.ReadUInt32();
selectedEffect = AfflictionPrefab.Prefabs.Find(a => a.UIntIdentifier == selectedEffectId);
}
}
}
}
@@ -1,13 +1,201 @@
using Microsoft.Xna.Framework;
using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Barotrauma.IO;
namespace Barotrauma.Items.Components
{
partial class IdCard
{
public Sprite StoredPortrait;
public Vector2 StoredSheetIndex;
public JobPrefab StoredJobPrefab;
public List<WearableSprite> StoredAttachments;
public struct OwnerAppearance
{
public Sprite Portrait;
public Vector2 SheetIndex;
public JobPrefab JobPrefab;
public List<WearableSprite> Attachments;
public Color HairColor;
public Color FacialHairColor;
public Color SkinColor;
public void ExtractJobPrefab(string[] tags)
{
string jobIdTag = tags.FirstOrDefault(s => s.StartsWith("jobid:"));
if (jobIdTag != null && jobIdTag.Length > 6)
{
string jobId = jobIdTag.Substring(6);
if (jobId != string.Empty)
{
JobPrefab = JobPrefab.Get(jobId);
}
}
}
public void ExtractAppearance(CharacterInfo characterInfo, string[] tags)
{
Gender disguisedGender = Gender.None;
Race disguisedRace = Race.None;
int disguisedHeadSpriteId = -1;
int disguisedHairIndex = -1;
int disguisedBeardIndex = -1;
int disguisedMoustacheIndex = -1;
int disguisedFaceAttachmentIndex = -1;
Color hairColor = Color.Black;
Color facialHairColor = Color.Black;
Color skinColor = Color.Black;
foreach (string tag in tags)
{
string[] s = tag.Split(':');
switch (s[0].ToLowerInvariant())
{
case "haircolor":
hairColor = XMLExtensions.ParseColor(s[1]);
break;
case "facialhaircolor":
facialHairColor = XMLExtensions.ParseColor(s[1]);
break;
case "skincolor":
skinColor = XMLExtensions.ParseColor(s[1]);
break;
case "gender":
Enum.TryParse(s[1], ignoreCase: true, out disguisedGender);
break;
case "race":
Enum.TryParse(s[1], ignoreCase: true, out disguisedRace);
break;
case "headspriteid":
int.TryParse(s[1], NumberStyles.Any, CultureInfo.InvariantCulture, out disguisedHeadSpriteId);
break;
case "hairindex":
disguisedHairIndex = int.Parse(s[1]);
break;
case "beardindex":
disguisedBeardIndex = int.Parse(s[1]);
break;
case "moustacheindex":
disguisedMoustacheIndex = int.Parse(s[1]);
break;
case "faceattachmentindex":
disguisedFaceAttachmentIndex = int.Parse(s[1]);
break;
case "sheetindex":
string[] vectorValues = s[1].Split(";");
SheetIndex = new Vector2(float.Parse(vectorValues[0]), float.Parse(vectorValues[1]));
break;
}
}
if ((characterInfo.HasGenders && disguisedGender == Gender.None)
|| (characterInfo.HasRaces && disguisedRace == Race.None)
|| disguisedHeadSpriteId <= 0)
{
Portrait = null;
Attachments = null;
return;
}
foreach (XElement limbElement in characterInfo.Ragdoll.MainElement.Elements())
{
if (!limbElement.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase)) { continue; }
XElement spriteElement = limbElement.Element("sprite");
if (spriteElement == null) { continue; }
string spritePath = spriteElement.Attribute("texture").Value;
spritePath = spritePath.Replace("[GENDER]", disguisedGender.ToString().ToLowerInvariant());
spritePath = spritePath.Replace("[RACE]", disguisedRace.ToString().ToLowerInvariant());
spritePath = spritePath.Replace("[HEADID]", disguisedHeadSpriteId.ToString());
string fileName = Path.GetFileNameWithoutExtension(spritePath);
//go through the files in the directory to find a matching sprite
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
{
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string fileWithoutTags = Path.GetFileNameWithoutExtension(file);
fileWithoutTags = fileWithoutTags.Split('[', ']').First();
if (fileWithoutTags != fileName) { continue; }
Portrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
break;
}
break;
}
if (characterInfo.Wearables != null)
{
float baldnessChance = disguisedGender == Gender.Female ? 0.05f : 0.2f;
List<XElement> createElementList(WearableType wearableType, float emptyCommonness = 1.0f)
=> CharacterInfo.AddEmpty(
characterInfo.FilterByTypeAndHeadID(
characterInfo.FilterElementsByGenderAndRace(characterInfo.Wearables, disguisedGender, disguisedRace),
wearableType, disguisedHeadSpriteId),
wearableType, emptyCommonness);
var disguisedHairs = createElementList(WearableType.Hair, baldnessChance);
var disguisedBeards = createElementList(WearableType.Beard);
var disguisedMoustaches = createElementList(WearableType.Moustache);
var disguisedFaceAttachments = createElementList(WearableType.FaceAttachment);
XElement getElementFromList(List<XElement> list, int index)
=> CharacterInfo.IsValidIndex(index, list)
? list[index]
: characterInfo.GetRandomElement(list);
var disguisedHairElement = getElementFromList(disguisedHairs, disguisedHairIndex);
var disguisedBeardElement = getElementFromList(disguisedBeards, disguisedBeardIndex);
var disguisedMoustacheElement = getElementFromList(disguisedMoustaches, disguisedMoustacheIndex);
var disguisedFaceAttachmentElement = getElementFromList(disguisedFaceAttachments, disguisedFaceAttachmentIndex);
Attachments = new List<WearableSprite>();
void loadAttachments(List<WearableSprite> attachments, XElement element, WearableType wearableType)
{
foreach (var s in element?.Elements("sprite") ?? Enumerable.Empty<XElement>())
{
attachments.Add(new WearableSprite(s, wearableType));
}
}
loadAttachments(Attachments, disguisedFaceAttachmentElement, WearableType.FaceAttachment);
loadAttachments(Attachments, disguisedBeardElement, WearableType.Beard);
loadAttachments(Attachments, disguisedMoustacheElement, WearableType.Moustache);
loadAttachments(Attachments, disguisedHairElement, WearableType.Hair);
loadAttachments(Attachments,
characterInfo.OmitJobInPortraitClothing
? JobPrefab.NoJobElement?.Element("PortraitClothing")
: JobPrefab?.ClothingElement,
WearableType.JobIndicator);
}
HairColor = hairColor;
FacialHairColor = facialHairColor;
SkinColor = skinColor;
}
}
public OwnerAppearance StoredOwnerAppearance = default;
}
}
@@ -7,6 +7,8 @@ using System.Collections.Generic;
using Barotrauma.IO;
using System.Text;
using System.Xml.Linq;
using Barotrauma.Sounds;
using System.Linq;
namespace Barotrauma.Items.Components
{
@@ -18,7 +20,11 @@ namespace Barotrauma.Items.Components
protected float currentCrossHairScale, currentCrossHairPointerScale;
private RoundSound chargeSound;
private SoundChannel chargeSoundChannel;
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
private readonly List<ParticleEmitter> particleEmitterCharges = new List<ParticleEmitter>();
[Serialize(1.0f, false, description: "The scale of the crosshair sprite (if there is one).")]
public float CrossHairScale
@@ -48,6 +54,12 @@ namespace Barotrauma.Items.Components
case "particleemitter":
particleEmitters.Add(new ParticleEmitter(subElement));
break;
case "particleemittercharge":
particleEmitterCharges.Add(new ParticleEmitter(subElement));
break;
case "chargesound":
chargeSound = Submarine.LoadRoundSound(subElement, false);
break;
}
}
}
@@ -84,15 +96,62 @@ namespace Barotrauma.Items.Components
crosshairPointerPos = PlayerInput.MousePosition;
}
partial void UpdateProjSpecific(float deltaTime)
{
float chargeRatio = currentChargeTime / MaxChargeTime;
switch (currentChargingState)
{
case ChargingState.WindingUp:
case ChargingState.WindingDown:
Vector2 particlePos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
float sizeMultiplier = Math.Clamp(chargeRatio, 0.1f, 1f);
foreach (ParticleEmitter emitter in particleEmitterCharges)
{
emitter.Emit(deltaTime, particlePos, hullGuess: null, sizeMultiplier: sizeMultiplier, colorMultiplier: emitter.Prefab.Properties.ColorMultiplier);
}
if (chargeSoundChannel == null || !chargeSoundChannel.IsPlaying)
{
if (chargeSound != null)
{
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound.Sound, item.WorldPosition, chargeSound.Volume, chargeSound.Range, ignoreMuffling: chargeSound.IgnoreMuffling);
if (chargeSoundChannel != null) chargeSoundChannel.Looping = true;
}
}
else if (chargeSoundChannel != null)
{
chargeSoundChannel.FrequencyMultiplier = MathHelper.Lerp(0.5f, 1.5f, chargeRatio);
}
break;
default:
if (chargeSoundChannel != null)
{
if (chargeSoundChannel.IsPlaying)
{
chargeSoundChannel.FadeOutAndDispose();
chargeSoundChannel.Looping = false;
}
else
{
chargeSoundChannel = null;
}
}
break;
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
//camera focused on some other item/device, don't draw the crosshair
if (character.ViewTarget != null && (character.ViewTarget is Item item) && item.Prefab.FocusOnSelected) { return; }
if (character.ViewTarget != null && (character.ViewTarget is Item viewTargetItem) && viewTargetItem.Prefab.FocusOnSelected) { return; }
//don't draw the crosshair if the item is in some other type of equip slot than hands (e.g. assault rifle in the bag slot)
if (!character.HeldItems.Contains(item)) { return; }
GUI.HideCursor = (crosshairSprite != null || crosshairPointerSprite != null) &&
GUI.MouseOn == null && !Inventory.IsMouseOnInventory() && !GameMain.Instance.Paused;
GUI.MouseOn == null && !Inventory.IsMouseOnInventory && !GameMain.Instance.Paused;
if (GUI.HideCursor)
{
crosshairSprite?.Draw(spriteBatch, crosshairPos, Color.White, 0, currentCrossHairScale);
@@ -246,6 +246,7 @@ namespace Barotrauma.Items.Components
public void PlaySound(ActionType type, Character user = null)
{
if (!hasSoundsOfType[(int)type]) { return; }
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
if (loopingSound != null)
{
@@ -429,7 +430,7 @@ namespace Barotrauma.Items.Components
}
foreach (ItemComponent component in item.Components)
{
if (component.name.ToLower() == LinkUIToComponent.ToLower())
if (component.name.Equals(LinkUIToComponent, StringComparison.OrdinalIgnoreCase))
{
linkToUIComponent = component;
}
@@ -443,9 +444,9 @@ namespace Barotrauma.Items.Components
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
public virtual void AddToGUIUpdateList()
public virtual void AddToGUIUpdateList(int order = 0)
{
GuiFrame?.AddToGUIUpdateList();
GuiFrame?.AddToGUIUpdateList(order: order);
}
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }
@@ -620,6 +621,6 @@ namespace Barotrauma.Items.Components
}
OnResolutionChanged();
}
public virtual void AddTooltipInfo(ref string description) { }
public virtual void AddTooltipInfo(ref string name, ref string description) { }
}
}
@@ -19,6 +19,8 @@ namespace Barotrauma.Items.Components
/// </summary>
private float[] containedSpriteDepths;
private Sprite[] slotIcons;
public Sprite InventoryTopSprite
{
get { return inventoryTopSprite; }
@@ -58,6 +60,9 @@ namespace Barotrauma.Items.Components
[Serialize(null, false)]
public string ContainedStateIndicatorStyle { get; set; }
[Serialize(-1, false, description: "Can be used to make the contained state indicator display the condition of the item in a specific slot even when the container's capacity is more than 1.")]
public int ContainedStateIndicatorSlot { get; set; }
[Serialize(true, false, description: "Should an indicator displaying the state of the contained items be displayed on this item's inventory slot. "+
"If this item can only contain one item, the indicator will display the condition of the contained item, otherwise it will indicate how full the item is.")]
public bool ShowContainedStateIndicator { get; set; }
@@ -85,6 +90,7 @@ namespace Barotrauma.Items.Components
partial void InitProjSpecific(XElement element)
{
slotIcons = new Sprite[capacity];
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -104,6 +110,17 @@ namespace Barotrauma.Items.Components
case "containedstateindicatorempty":
ContainedStateIndicatorEmpty = new Sprite(subElement);
break;
case "sloticon":
int index = subElement.GetAttributeInt("slotindex", -1);
Sprite icon = new Sprite(subElement);
for (int i = 0; i < capacity; i++)
{
if (i == index || index == -1)
{
slotIcons[i] = icon;
}
}
break;
}
}
@@ -197,7 +214,7 @@ namespace Barotrauma.Items.Components
if (UILabel == string.Empty) { return string.Empty; }
if (UILabel != null)
{
return TextManager.Get("UILabel." + UILabel);
return TextManager.Get("UILabel." + UILabel, returnNull: true) ?? TextManager.Get(UILabel);
}
else
{
@@ -205,6 +222,12 @@ namespace Barotrauma.Items.Components
}
}
public Sprite GetSlotIcon(int slotIndex)
{
if (slotIndex < 0 || slotIndex >= slotIcons.Length) { return null; }
return slotIcons[slotIndex];
}
public bool KeepOpenWhenEquippedBy(Character character)
{
if (!character.CanAccessInventory(Inventory) ||
@@ -266,7 +289,7 @@ namespace Barotrauma.Items.Components
}
else
{
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
Matrix transform = Matrix.CreateRotationZ(item.body.DrawRotation);
if (item.body.Dir == -1.0f)
{
transformedItemPos.X = -transformedItemPos.X;
@@ -277,7 +300,7 @@ namespace Barotrauma.Items.Components
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
transformedItemPos += item.DrawPosition;
transformedItemPos += item.body.DrawPosition;
}
Vector2 currentItemPos = transformedItemPos;
@@ -319,7 +342,7 @@ namespace Barotrauma.Items.Components
new Vector2(currentItemPos.X, -currentItemPos.Y),
isWiringMode ? containedItem.GetSpriteColor() * 0.15f : containedItem.GetSpriteColor(),
origin,
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation + MathHelper.ToRadians(-item.Rotation)),
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation ),
containedItem.Scale,
spriteEffects,
depth: containedSpriteDepth);
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
{
Vector2 origin = Light.LightSprite.Origin;
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
@@ -14,12 +14,22 @@ namespace Barotrauma.Items.Components
}
private GUIButton activateButton;
private GUIComponent inputInventoryHolder, outputInventoryHolder;
private GUICustomComponent inputInventoryOverlay;
private GUIComponent inSufficientPowerWarning;
private bool pendingState;
private GUITextBlock infoArea;
[Serialize("DeconstructorDeconstruct", true)]
public string ActivateButtonText { get; set; }
[Serialize("", true)]
public string InfoText { get; set; }
[Serialize(0.0f, true)]
public float InfoAreaWidth { get; set; }
partial void InitProjSpecific(XElement element)
{
CreateGUI();
@@ -39,6 +49,12 @@ namespace Barotrauma.Items.Components
RelativeSpacing = 0.08f
};
new GUITextBlock(new RectTransform(new Vector2(1f, 0.07f), paddedFrame.RectTransform), item.Name, font: GUI.SubHeadingFont)
{
TextAlignment = Alignment.Center,
AutoScaleHorizontal = true
};
var topFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), paddedFrame.RectTransform), style: null);
// === INPUT LABEL === //
@@ -55,22 +71,23 @@ namespace Barotrauma.Items.Components
// === INPUT SLOTS === //
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
// === ACTIVATE BUTTON === //
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.7f), inputArea.RectTransform), childAnchor: Anchor.CenterLeft);
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterLeft);
activateButton = new GUIButton(new RectTransform(new Vector2(0.95f, 0.8f), buttonContainer.RectTransform), TextManager.Get("DeconstructorDeconstruct"), style: "DeviceButton")
{
TextBlock = { AutoScaleHorizontal = true },
OnClicked = ToggleActive
};
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
TextManager.Get("DeconstructorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
TextManager.Get("DeconstructorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
{
HoverColor = Color.Black,
IgnoreLayoutGroups = true,
Visible = false,
CanBeFocused = false
CanBeFocused = false,
AutoScaleHorizontal = true
};
// === OUTPUT AREA === //
@@ -86,8 +103,70 @@ namespace Barotrauma.Items.Components
outputLabel.RectTransform.Resize(new Point((int) outputLabel.Font.MeasureString(outputLabel.Text).X, outputLabel.RectTransform.Rect.Height));
new GUIFrame(new RectTransform(Vector2.One, outputLabelArea.RectTransform), style: "HorizontalLine");
// === OUTPUT SLOTS === //
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), style: null);
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.BottomLeft, isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
// === OUTPUT SLOTS === //
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f - InfoAreaWidth, 1f), outputArea.RectTransform, Anchor.CenterLeft), style: null);
if (InfoAreaWidth >= 0.0f)
{
var infoAreaContainer = new GUILayoutGroup(new RectTransform(new Vector2(InfoAreaWidth, 0.8f), outputArea.RectTransform), childAnchor: Anchor.CenterLeft);
infoArea = new GUITextBlock(new RectTransform(new Vector2(0.95f, 0.95f), infoAreaContainer.RectTransform), string.Empty, wrap: true);
}
ActivateButton.OnAddedToGUIUpdateList += (GUIComponent component) =>
{
activateButton.Enabled = true;
if (string.IsNullOrEmpty(InfoText))
{
infoArea.Text = string.Empty;
}
else
{
infoArea.Text = TextManager.Get(InfoText, returnNull: true) ?? InfoText;
}
if (IsActive)
{
activateButton.Text = TextManager.Get("DeconstructorCancel");
infoArea.Text = string.Empty;
return;
}
bool outputsFound = false;
foreach (var (inputItem, deconstructItem) in GetAvailableOutputs(checkRequiredOtherItems: true))
{
outputsFound = true;
if (!string.IsNullOrEmpty(deconstructItem.ActivateButtonText))
{
string buttonText = TextManager.Get(deconstructItem.ActivateButtonText, returnNull: true) ?? deconstructItem.ActivateButtonText;
string infoText = string.Empty;
if (!string.IsNullOrEmpty(deconstructItem.InfoText))
{
infoText = TextManager.Get(deconstructItem.InfoText, returnNull: true) ?? deconstructItem.InfoText;
}
inputItem.GetComponent<GeneticMaterial>()?.ModifyDeconstructInfo(this, ref buttonText, ref infoText);
activateButton.Text = buttonText;
if (infoArea != null)
{
infoArea.Text = infoText;
}
return;
}
}
//no valid outputs found: check if we're missing some required items from the input slots and display a message about it if possible
if (!outputsFound && infoArea != null)
{
foreach (var (inputItem, deconstructItem) in GetAvailableOutputs(checkRequiredOtherItems: false))
{
if (deconstructItem.RequiredOtherItem.Any() && !string.IsNullOrEmpty(deconstructItem.InfoTextOnOtherItemMissing))
{
string missingItemName = TextManager.Get("entityname." + deconstructItem.RequiredOtherItem.First(), returnNull: true);
infoArea.Text = TextManager.GetWithVariable(deconstructItem.InfoTextOnOtherItemMissing, "[itemname]", missingItemName);
}
}
}
activateButton.Enabled = outputsFound;
activateButton.Text = TextManager.Get(ActivateButtonText);
};
}
public override bool Select(Character character)
@@ -126,13 +205,30 @@ namespace Barotrauma.Items.Components
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
overlayComponent.RectTransform.SetAsLastChild();
var lastSlot = inputContainer.Inventory.visualSlots.Last();
GUI.DrawRectangle(spriteBatch,
new Rectangle(
lastSlot.Rect.X, lastSlot.Rect.Y + (int)(lastSlot.Rect.Height * (1.0f - progressState)),
lastSlot.Rect.Width, (int)(lastSlot.Rect.Height * progressState)),
GUI.Style.Green * 0.5f, isFilled: true);
if (!(inputContainer?.Inventory?.visualSlots is { } visualSlots)) { return; }
if (DeconstructItemsSimultaneously)
{
for (int i = 0; i < InputContainer.Inventory.Capacity; i++)
{
if (InputContainer.Inventory.GetItemAt(i) == null) { continue; }
DrawProgressBar(InputContainer.Inventory.visualSlots[i]);
}
}
else
{
DrawProgressBar(inputContainer.Inventory.visualSlots.Last());
}
void DrawProgressBar(VisualSlot slot)
{
GUI.DrawRectangle(spriteBatch,
new Rectangle(
slot.Rect.X, slot.Rect.Y + (int)(slot.Rect.Height * (1.0f - progressState)),
slot.Rect.Width, (int)(slot.Rect.Height * progressState)),
GUI.Style.Green * 0.5f, isFilled: true);
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
@@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components
private FabricationRecipe pendingFabricatedItem;
private Pair<Rectangle, string> tooltip;
private (Rectangle area, string text)? tooltip;
private GUITextBlock requiredTimeBlock;
@@ -255,19 +255,22 @@ namespace Barotrauma.Items.Components
var item1 = c1.GUIComponent.UserData as FabricationRecipe;
var item2 = c2.GUIComponent.UserData as FabricationRecipe;
bool hasSkills1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
bool hasSkills2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
int itemPlacement1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f ? 0 : -1;
int itemPlacement2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f ? 0 : -1;
if (hasSkills1 != hasSkills2)
itemPlacement1 += item1.RequiresRecipe && !character.HasRecipeForItem(item1.TargetItem.Identifier) ? -2 : 0;
itemPlacement2 += item2.RequiresRecipe && !character.HasRecipeForItem(item2.TargetItem.Identifier) ? -2 : 0;
if (itemPlacement1 != itemPlacement2)
{
return hasSkills1 ? -1 : 1;
return itemPlacement1 > itemPlacement2 ? -1 : 1;
}
return string.Compare(item1.DisplayName, item2.DisplayName);
});
var sufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
TextManager.Get("fabricatorsufficientskills", returnNull: true) ?? "Sufficient skills to fabricate", textColor: GUI.Style.Green, font: GUI.SubHeadingFont)
TextManager.Get("fabricatorsufficientskills"), textColor: GUI.Style.Green, font: GUI.SubHeadingFont)
{
AutoScaleHorizontal = true,
CanBeFocused = false
@@ -275,7 +278,7 @@ namespace Barotrauma.Items.Components
sufficientSkillsText.RectTransform.SetAsFirstChild();
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
TextManager.Get("fabricatorinsufficientskills", returnNull: true) ?? "Insufficient skills to fabricate", textColor: Color.Orange, font: GUI.SubHeadingFont)
TextManager.Get("fabricatorinsufficientskills"), textColor: Color.Orange, font: GUI.SubHeadingFont)
{
AutoScaleHorizontal = true,
CanBeFocused = false
@@ -285,6 +288,18 @@ namespace Barotrauma.Items.Components
{
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
}
var requiresRecipeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
TextManager.Get("fabricatorrequiresrecipe"), textColor: Color.Red, font: GUI.SubHeadingFont)
{
AutoScaleHorizontal = true,
CanBeFocused = false
};
var firstRequiresRecipe = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricationRecipe fabricableItem && (fabricableItem.RequiresRecipe && !character.HasRecipeForItem(fabricableItem.TargetItem.Identifier)));
if (firstRequiresRecipe != null)
{
requiresRecipeText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstRequiresRecipe.RectTransform));
}
}
private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
@@ -297,6 +312,7 @@ namespace Barotrauma.Items.Components
int slotIndex = 0;
var missingItems = new List<FabricationRecipe.RequiredItem>();
foreach (FabricationRecipe.RequiredItem requiredItem in targetItem.RequiredItems)
{
for (int i = 0; i < requiredItem.Amount; i++)
@@ -308,6 +324,8 @@ namespace Barotrauma.Items.Components
{
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefabs.Contains(item.prefab)));
}
var missingCounts = missingItems.GroupBy(missingItem => missingItem).ToDictionary(x => x.Key, x => x.Count());
missingItems = missingItems.Distinct().ToList();
var availableIngredients = GetAvailableIngredients();
@@ -318,30 +336,30 @@ namespace Barotrauma.Items.Components
slotIndex++;
}
//highlight suitable ingredients in linked inventories
foreach (Item item in availableIngredients)
{
if (item.ParentInventory != inputContainer.Inventory && IsItemValidIngredient(item, requiredItem))
{
int availableSlotIndex = item.ParentInventory.FindIndex(item);
//slots are null if the inventory has never been displayed
//(linked item, but the UI is not set to be displayed at the same time)
if (item.ParentInventory.visualSlots != null)
{
if (item.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
{
item.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
if (slotIndex < inputContainer.Capacity)
requiredItem.ItemPrefabs
.Where(requiredPrefab => availableIngredients.ContainsKey(requiredPrefab.Identifier))
.ForEach(requiredPrefab => {
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
availablePrefabs
.Where(availablePrefab => availablePrefab.ParentInventory != inputContainer.Inventory)
.Where(availablePrefab => availablePrefab.ParentInventory.visualSlots != null) //slots are null if the inventory has never been displayed
.ForEach(availablePrefab => { //(linked item, but the UI is not set to be displayed at the same time)
int availableSlotIndex = availablePrefab.ParentInventory.FindIndex(availablePrefab);
if (availablePrefab.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
{
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
availablePrefab.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
if (slotIndex < inputContainer.Capacity)
{
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
}
}
}
}
}
}
});
});
if (slotIndex >= inputContainer.Capacity) { break; }
var itemIcon = requiredItem.ItemPrefabs.First().InventoryIcon ?? requiredItem.ItemPrefabs.First().sprite;
Rectangle slotRect = inputContainer.Inventory.visualSlots[slotIndex].Rect;
itemIcon.Draw(
@@ -350,11 +368,32 @@ namespace Barotrauma.Items.Components
color: requiredItem.ItemPrefabs.First().InventoryIconColor * 0.3f,
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
if (missingCounts[requiredItem] > 1)
{
Vector2 stackCountPos = new Vector2(slotRect.Right, slotRect.Bottom);
string stackCountText = "x" + missingCounts[requiredItem];
stackCountPos -= GUI.SmallFont.MeasureString(stackCountText) + new Vector2(4, 2);
GUI.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos + Vector2.One, Color.Black);
GUI.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, Color.White);
}
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X, slotRect.Bottom - 8, slotRect.Width, 8), Color.Black * 0.8f, true);
DrawConditionBar(spriteBatch, requiredItem.MinCondition);
}
else if (requiredItem.MaxCondition < 1.0f)
{
DrawConditionBar(spriteBatch, requiredItem.MaxCondition);
}
void DrawConditionBar(SpriteBatch sb, float condition)
{
int spacing = GUI.IntScale(4);
int height = GUI.IntScale(10);
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X + spacing, slotRect.Bottom - spacing - height, slotRect.Width - spacing * 2, height), Color.Black * 0.8f, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(slotRect.X, slotRect.Bottom - 8, (int)(slotRect.Width * requiredItem.MinCondition), 8),
new Rectangle(slotRect.X + spacing, slotRect.Bottom - spacing - height, (int)((slotRect.Width - spacing * 2) * condition), height),
GUI.Style.Green * 0.8f, true);
}
@@ -367,6 +406,10 @@ namespace Barotrauma.Items.Components
{
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
}
else if(requiredItem.MaxCondition < 1.0f)
{
toolTipText += " 0-" + (int)Math.Round(requiredItem.MaxCondition * 100) + "%";
}
else if (requiredItem.MaxCondition <= 0.0f)
{
toolTipText = TextManager.GetWithVariable("displayname.emptyitem", "[itemname]", toolTipText);
@@ -375,7 +418,7 @@ namespace Barotrauma.Items.Components
{
toolTipText += '\n' + requiredItem.ItemPrefabs.First().Description;
}
tooltip = new Pair<Rectangle, string>(slotRect, toolTipText);
tooltip = (slotRect, toolTipText);
}
slotIndex++;
@@ -415,7 +458,7 @@ namespace Barotrauma.Items.Components
if (tooltip != null)
{
GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First);
GUIComponent.DrawToolTip(spriteBatch, tooltip.Value.text, tooltip.Value.area);
tooltip = null;
}
}
@@ -435,6 +478,22 @@ namespace Barotrauma.Items.Components
if (recipe?.DisplayName == null) { continue; }
child.Visible = recipe.DisplayName.ToLower().Contains(filter);
}
//go through the elements backwards, and disable the labels ("insufficient skills to fabricate", "recipe required...") if there's no items below them
bool recipeVisible = false;
foreach (GUIComponent child in itemList.Content.Children.Reverse())
{
if (!(child.UserData is FabricationRecipe recipe))
{
child.Visible = recipeVisible;
recipeVisible = false;
}
else
{
recipeVisible = child.Visible;
}
}
itemList.UpdateScrollBarSize();
itemList.BarScroll = 0.0f;
@@ -470,14 +529,30 @@ namespace Barotrauma.Items.Components
};
}*/
string itemName = GetRecipeNameAndAmount(selectedItem);
string name = itemName;
float quality = GetFabricatedItemQuality(selectedItem, user);
if (quality > 0)
{
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName + '\n', fallBackTag: "itemname.quality3");
}
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
GetRecipeNameAndAmount(selectedItem), textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont)
name, textAlignment: Alignment.TopLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont, parseRichText: true)
{
AutoScaleHorizontal = true
};
nameBlock.Padding = new Vector4(0, nameBlock.Padding.Y, nameBlock.Padding.Z, nameBlock.Padding.W);
nameBlock.Padding = new Vector4(0, nameBlock.Padding.Y, GUI.IntScale(5), nameBlock.Padding.W);
if (nameBlock.TextScale < 0.7f)
{
nameBlock.SetRichText(TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName, fallBackTag: "itemname.quality3"));
nameBlock.AutoScaleHorizontal = false;
nameBlock.TextScale = 0.7f;
nameBlock.Wrap = true;
nameBlock.SetTextPos();
nameBlock.RectTransform.MinSize = new Point(0, (int)(nameBlock.TextSize.Y * nameBlock.TextScale));
}
if (!string.IsNullOrWhiteSpace(selectedItem.TargetItem.Description))
{
@@ -489,6 +564,7 @@ namespace Barotrauma.Items.Components
while (description.Rect.Height + nameBlock.Rect.Height > paddedFrame.Rect.Height)
{
var lines = description.WrappedText.Split('\n');
if (lines.Length <= 1) { break; }
var newString = string.Join('\n', lines.Take(lines.Length - 1));
description.Text = newString.Substring(0, newString.Length - 4) + "...";
description.CalculateHeightFromText();
@@ -598,10 +674,15 @@ namespace Barotrauma.Items.Components
{
foreach (GUIComponent child in itemList.Content.Children)
{
var itemPrefab = child.UserData as FabricationRecipe;
if (itemPrefab == null) continue;
if (!(child.UserData is FabricationRecipe itemPrefab)) { continue; }
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients);
if (itemPrefab != selectedItem &&
(child.Rect.Y > itemList.Rect.Bottom || child.Rect.Bottom < itemList.Rect.Y))
{
continue;
}
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients, character);
if (itemPrefab == selectedItem)
{
activateButton.Enabled = canBeFabricated;
File diff suppressed because it is too large Load Diff
@@ -142,6 +142,7 @@ namespace Barotrauma.Items.Components
partial void UpdateProjSpecific(float deltaTime)
{
float rotationRad = MathHelper.ToRadians(item.Rotation);
if (FlowPercentage < 0.0f)
{
foreach (var (position, emitter) in pumpOutEmitters)
@@ -149,12 +150,13 @@ namespace Barotrauma.Items.Components
if (item.CurrentHull != null && item.CurrentHull.Surface < item.Rect.Location.Y + position.Y) { continue; }
//only emit "pump out" particles when underwater
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
float angle = 0.0f;
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
float angle = -rotationRad;
if (item.FlippedX)
{
relativeParticlePos.X = -relativeParticlePos.X;
angle = MathHelper.Pi;
angle += MathHelper.Pi;
}
if (item.FlippedY)
{
@@ -170,11 +172,12 @@ namespace Barotrauma.Items.Components
foreach (var (position, emitter) in pumpInEmitters)
{
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
float angle = 0.0f;
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
float angle = -rotationRad;
if (item.FlippedX)
{
relativeParticlePos.X = -relativeParticlePos.X;
angle = MathHelper.Pi;
angle += MathHelper.Pi;
}
if (item.FlippedY)
{
@@ -134,6 +134,14 @@ namespace Barotrauma.Items.Components
private static string caveLabel;
[Serialize(false, false)]
public bool RightLayout
{
get;
set;
}
private bool AllowUsingMineralScanner =>
HasMineralScanner && !isConnectedToSteering;
@@ -316,7 +324,7 @@ namespace Barotrauma.Items.Components
"", warningColor, GUI.LargeFont, Alignment.Center);
// Setup layout for nav terminal
if (isConnectedToSteering)
if (isConnectedToSteering || RightLayout)
{
controlContainer.RectTransform.RelativeOffset = controlBoxOffset;
controlContainer.RectTransform.SetPosition(Anchor.TopRight);
@@ -446,13 +454,8 @@ namespace Barotrauma.Items.Components
zoomSlider.BarScroll += PlayerInput.ScrollWheelSpeed / 1000.0f;
zoomSlider.OnMoved(zoomSlider, zoomSlider.BarScroll);
}
if (PlayerInput.KeyHit(InputType.Run))
{
SonarModeSwitch.OnClicked(SonarModeSwitch, null);
}
}
float distort = 1.0f - item.Condition / item.MaxCondition;
for (int i = sonarBlips.Count - 1; i >= 0; i--)
{
@@ -885,7 +888,7 @@ namespace Barotrauma.Items.Components
foreach (AITarget aiTarget in AITarget.List)
{
if (!aiTarget.Enabled) { continue; }
if (aiTarget.InDetectable) { continue; }
if (string.IsNullOrEmpty(aiTarget.SonarLabel) || aiTarget.SoundRange <= 0.0f) { continue; }
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange)
@@ -1239,7 +1242,7 @@ namespace Barotrauma.Items.Components
foreach (AITarget aiTarget in AITarget.List)
{
float disruption = aiTarget.Entity is Character c ? c.Params.SonarDisruption : aiTarget.SonarDisruption;
if (disruption <= 0.0f || !aiTarget.Enabled) { continue; }
if (disruption <= 0.0f || aiTarget.InDetectable) { continue; }
float distSqr = Vector2.DistanceSquared(aiTarget.WorldPosition, pingSource);
if (distSqr > worldPingRadiusSqr) { continue; }
float disruptionDist = (float)Math.Sqrt(distSqr);
@@ -1364,28 +1367,6 @@ namespace Barotrauma.Items.Components
blipType : cell.IsDestructible ? BlipType.Destructible : BlipType.Default);
}
}
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
{
if (!MathUtils.CircleIntersectsRectangle(pingSource, range, ruin.Area)) continue;
foreach (var ruinShape in ruin.RuinShapes)
{
foreach (RuinGeneration.Line wall in ruinShape.Walls)
{
float cellDot = Vector2.Dot(
Vector2.Normalize(ruinShape.Center - pingSource),
Vector2.Normalize((wall.A + wall.B) / 2.0f - ruinShape.Center));
if (cellDot > 0) continue;
CreateBlipsForLine(
wall.A, wall.B,
pingSource, transducerPos,
pingRadius, prevPingRadius,
100.0f, 1000.0f, range, pingStrength, passive);
}
}
}
}
foreach (Item item in Item.ItemList)
@@ -1634,7 +1615,7 @@ namespace Barotrauma.Items.Components
void CalculateDistance()
{
pathFinder ??= new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
pathFinder ??= new PathFinder(WayPoint.WayPointList, false);
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(transducerPosition), ConvertUnits.ToSimUnits(worldPosition));
if (!path.Unreachable)
{
@@ -888,6 +888,7 @@ namespace Barotrauma.Items.Components
maintainPosOriginIndicator?.Remove();
steeringIndicator?.Remove();
enterOutpostPrompt?.Close();
pathFinder = null;
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
@@ -71,7 +71,7 @@ namespace Barotrauma.Items.Components
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), textArea.RectTransform, Anchor.CenterRight),
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
{
TextGetter = () => $"{(int)charge}/{(int)capacity} {kWmin} ({((int)MathUtils.Percentage(charge, capacity)).ToString()} %)"
TextGetter = () => $"{(int)Math.Round(charge)}/{(int)capacity} {kWmin} ({(int)Math.Round(MathUtils.Percentage(charge, capacity))} %)"
};
if (chargeText.TextSize.X > chargeText.Rect.Width) { chargeText.Font = GUI.SmallFont; }
@@ -0,0 +1,21 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Quality : ItemComponent
{
public override void AddTooltipInfo(ref string name, ref string description)
{
foreach (var statValue in statValues)
{
int roundedValue = (int)Math.Round(statValue.Value * qualityLevel * 100);
if (roundedValue == 0) { return; }
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("+0;-#")}%‖color:end‖ {TextManager.Get("qualitystattypenames." + statValue.Key.ToString(), true) ?? statValue.Key.ToString()}";
}
}
}
}
@@ -0,0 +1,22 @@
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
partial class RemoteController : ItemComponent
{
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
currentTarget?.DrawHUD(spriteBatch, Screen.Selected.Cam, character);
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
currentTarget?.UpdateHUD(cam, character,deltaTime);
}
public override void AddToGUIUpdateList(int order = 0)
{
currentTarget?.AddToGUIUpdateList(order: -1);
}
}
}
@@ -15,16 +15,23 @@ namespace Barotrauma.Items.Components
public GUIButton SabotageButton { get; private set; }
public GUIButton TinkerButton { get; private set; }
private GUIProgressBar progressBar;
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
private GUITextBlock progressBarOverlayText;
private GUILayoutGroup extraButtonContainer;
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
//the corresponding particle emitter is active when the condition is within this range
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
private readonly List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
private SoundChannel repairSoundChannel;
private string repairButtonText, repairingText;
private string sabotageButtonText, sabotagingText;
private string tinkerButtonText, tinkeringText;
private FixActions requestStartFixAction;
@@ -45,8 +52,24 @@ namespace Barotrauma.Items.Components
public override bool ShouldDrawHUD(Character character)
{
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false;
return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition)));
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) { return false; }
if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; }
float maxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(character);
if (item.Condition / maxRepairConditionMultiplier < RepairThreshold) { return true; }
if (CurrentFixer == character)
{
float condition = item.Condition / item.MaxRepairConditionMultiplier;
float maxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
if (condition < maxCondition * maxRepairConditionMultiplier)
{
return true;
}
}
if (IsTinkerable(character)) { return true; }
return false;
}
partial void InitProjSpecific(XElement element)
@@ -85,7 +108,7 @@ namespace Barotrauma.Items.Components
}
}
private void CreateGUI()
protected override void CreateGUI()
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.75f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
@@ -120,6 +143,11 @@ namespace Barotrauma.Items.Components
progressBar = new GUIProgressBar(new RectTransform(new Vector2(0.6f, 1.0f), progressBarHolder.RectTransform),
color: GUI.Style.Green, barSize: 0.0f, style: "DeviceProgressBar");
progressBarOverlayText = new GUITextBlock(new RectTransform(Vector2.One, progressBar.RectTransform), string.Empty, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
{
IgnoreLayoutGroups = true
};
repairButtonText = TextManager.Get("RepairButton");
repairingText = TextManager.Get("Repairing");
RepairButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), progressBarHolder.RectTransform, Anchor.TopCenter), repairButtonText)
@@ -135,9 +163,16 @@ namespace Barotrauma.Items.Components
progressBarHolder.RectTransform.MinSize = RepairButton.RectTransform.MinSize;
RepairButton.RectTransform.MinSize = new Point((int)(RepairButton.TextBlock.TextSize.X * 1.2f), RepairButton.RectTransform.MinSize.Y);
extraButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), isHorizontal: true)
{
IgnoreLayoutGroups = true,
Stretch = true,
AbsoluteSpacing = GUI.IntScale(5)
};
sabotageButtonText = TextManager.Get("SabotageButton");
sabotagingText = TextManager.Get("Sabotaging");
SabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText, style: "GUIButtonSmall")
SabotageButton = new GUIButton(new RectTransform(Vector2.One, extraButtonContainer.RectTransform), sabotageButtonText, style: "GUIButtonSmall")
{
IgnoreLayoutGroups = true,
Visible = false,
@@ -148,6 +183,22 @@ namespace Barotrauma.Items.Components
return true;
}
};
tinkerButtonText = TextManager.Get("TinkerButton", returnNull: true) ?? "Tinker";
tinkeringText = TextManager.Get("Tinkering", returnNull: true) ?? "Tinkering";
TinkerButton = new GUIButton(new RectTransform(Vector2.One, extraButtonContainer.RectTransform), tinkerButtonText, style: "GUIButtonSmall")
{
IgnoreLayoutGroups = true,
Visible = false,
OnClicked = (btn, obj) =>
{
requestStartFixAction = FixActions.Tinker;
item.CreateClientEvent(this);
return true;
}
};
extraButtonContainer.RectTransform.MinSize = new Point(0, SabotageButton.RectTransform.MinSize.Y);
}
partial void UpdateProjSpecific(float deltaTime)
@@ -176,6 +227,7 @@ namespace Barotrauma.Items.Components
{
case FixActions.Repair:
case FixActions.Sabotage:
case FixActions.Tinker:
StartRepairing(Character.Controlled, requestStartFixAction);
requestStartFixAction = FixActions.None;
break;
@@ -211,10 +263,24 @@ namespace Barotrauma.Items.Components
{
IsActive = true;
progressBar.BarSize = item.Condition / item.MaxCondition;
float defaultMaxCondition = (item.MaxCondition / item.MaxRepairConditionMultiplier);
progressBar.BarSize = item.Condition / defaultMaxCondition;
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green);
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition;
if (item.Condition > defaultMaxCondition)
{
float extraCondition = item.MaxCondition * (item.MaxRepairConditionMultiplier - 1.0f);
progressBar.Color = ToolBox.GradientLerp((item.Condition - defaultMaxCondition) / extraCondition, GUI.Style.ColorReputationHigh, GUI.Style.ColorReputationVeryHigh);
progressBarOverlayText.Visible = true;
progressBarOverlayText.Text = $"{(int)Math.Round((item.Condition / defaultMaxCondition) * 100)}%";
}
else
{
progressBarOverlayText.Visible = false;
}
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && item.ConditionPercentage < RepairThreshold;
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
repairButtonText :
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
@@ -226,7 +292,18 @@ namespace Barotrauma.Items.Components
sabotageButtonText :
sabotagingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
TinkerButton.Visible = IsTinkerable(character);
TinkerButton.IgnoreLayoutGroups = !TinkerButton.Visible;
TinkerButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Tinker)) && CanTinker(character);
TinkerButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Tinker) ?
tinkerButtonText :
tinkeringText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
extraButtonContainer.Visible = SabotageButton.Visible || TinkerButton.Visible;
extraButtonContainer.IgnoreLayoutGroups = !extraButtonContainer.Visible;
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
{
if (!(c.UserData is Skill skill)) continue;
@@ -278,9 +355,12 @@ namespace Barotrauma.Items.Components
deteriorationTimer = msg.ReadSingle();
deteriorateAlwaysResetTimer = msg.ReadSingle();
DeteriorateAlways = msg.ReadBoolean();
tinkeringDuration = msg.ReadSingle();
tinkeringStrength = msg.ReadSingle();
ushort currentFixerID = msg.ReadUInt16();
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer);
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
@@ -31,6 +31,9 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize("0.5,0.5)", false)]
public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f);
public Vector2 DrawSize
{
get
@@ -57,7 +60,6 @@ namespace Barotrauma.Items.Components
sourcePos = sourceLimb.body.DrawPosition;
}
return sourcePos;
}
partial void InitProjSpecific(XElement element)
@@ -81,13 +83,15 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (target == null) { return; }
if (target == null || target.Removed) { return; }
if (target.ParentInventory != null) { return; }
Vector2 startPos = GetSourcePos();
startPos.Y = -startPos.Y;
if (source is Item sourceItem)
{
var turret = sourceItem?.GetComponent<Turret>();
var turret = sourceItem.GetComponent<Turret>();
var weapon = sourceItem.GetComponent<RangedWeapon>();
if (turret != null)
{
startPos = new Vector2(sourceItem.WorldRect.X + turret.TransformedBarrelPos.X, -(sourceItem.WorldRect.Y - turret.TransformedBarrelPos.Y));
@@ -96,8 +100,21 @@ namespace Barotrauma.Items.Components
startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
}
}
else if (weapon != null)
{
Vector2 barrelPos = FarseerPhysics.ConvertUnits.ToDisplayUnits(weapon.TransformedBarrelPos);
barrelPos.Y = -barrelPos.Y;
startPos += barrelPos;
}
}
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
Vector2 endPos = new Vector2(target.DrawPosition.X, target.DrawPosition.Y);
Vector2 flippedPos = target.Sprite.size * target.Scale * (Origin - new Vector2(0.5f));
if (target.body.Dir < 0.0f)
{
flippedPos.X = -flippedPos.X;
}
endPos += Vector2.Transform(flippedPos, Matrix.CreateRotationZ(target.body.Rotation));
endPos.Y = -endPos.Y;
if (Snapped)
{
@@ -0,0 +1,29 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class Scanner : ItemComponent, IServerSerializable
{
partial void UpdateProjSpecific()
{
if (Holdable != null && Holdable.Attached && (AlwaysDisplayProgressBar || DisplayProgressBar) && !IsScanCompleted)
{
Character.Controlled?.UpdateHUDProgressBar(this,
item.WorldPosition,
ScanTimer / ScanDuration,
GUI.Style.Red, GUI.Style.Green,
textTag: "progressbar.scanning");
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
bool wasScanCompletedPreviously = IsScanCompleted;
scanTimer = msg.ReadSingle();
if (!wasScanCompletedPreviously && IsScanCompleted)
{
OnScanCompleted?.Invoke(this);
}
}
}
}
@@ -0,0 +1,115 @@
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class ButtonTerminal : ItemComponent, IClientSerializable, IServerSerializable
{
private string[] terminalButtonStyles;
private GUIFrame containerHolder;
private GUIImage containerIndicator;
private GUIComponentStyle indicatorStyleRed, indicatorStyleGreen;
partial void InitProjSpecific(XElement element)
{
terminalButtonStyles = new string[RequiredSignalCount];
int i = 0;
foreach (var childElement in element.GetChildElements("TerminalButton"))
{
string style = childElement.GetAttributeString("style", null);
if (style == null) { continue; }
terminalButtonStyles[i++] = style;
}
indicatorStyleRed = GUI.Style.GetComponentStyle("IndicatorLightRed");
indicatorStyleGreen = GUI.Style.GetComponentStyle("IndicatorLightGreen");
CreateGUI();
}
protected override void CreateGUI()
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
RelativeSpacing = 0.08f
};
paddedFrame.OnAddedToGUIUpdateList += (component) =>
{
bool buttonsEnabled = AllowUsingButtons;
foreach (var child in component.Children)
{
if (!(child is GUIButton)) { continue; }
if (!(child.UserData is int)) { continue; }
child.Enabled = buttonsEnabled;
child.Children.ForEach(c => c.Enabled = buttonsEnabled);
}
bool itemsContained = Container.Inventory.AllItems.Any();
if (itemsContained)
{
var indicatorStyle = buttonsEnabled ? indicatorStyleGreen : indicatorStyleRed;
if (containerIndicator.Style != indicatorStyle)
{
containerIndicator.ApplyStyle(indicatorStyle);
}
}
containerIndicator.OverrideState = itemsContained ? GUIComponent.ComponentState.Selected : GUIComponent.ComponentState.None;
};
float x = 1.0f / (1 + RequiredSignalCount);
float y = Math.Min((x * paddedFrame.Rect.Width) / paddedFrame.Rect.Height, 0.5f);
Vector2 relativeSize = new Vector2(x, y);
var containerSection = new GUIFrame(new RectTransform(new Vector2(x, 1.0f), paddedFrame.RectTransform), style: null);
var containerSlot = new GUIFrame(new RectTransform(new Vector2(1.0f, y), containerSection.RectTransform, anchor: Anchor.Center), style: null);
containerHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1.2f), containerSlot.RectTransform, Anchor.BottomCenter), style: null);
containerIndicator = new GUIImage(new RectTransform(new Vector2(0.5f, 0.5f * (1.0f - y)), containerSection.RectTransform, anchor: Anchor.BottomCenter),
style: "IndicatorLightRed", scaleToFit: true);
for (int i = 0; i < RequiredSignalCount; i++)
{
var button = new GUIButton(new RectTransform(relativeSize, paddedFrame.RectTransform), style: null)
{
UserData = i,
OnClicked = (button, userData) =>
{
if (GameMain.IsSingleplayer)
{
SendSignal((int)userData);
}
else
{
item.CreateClientEvent(this, new object[] { userData });
}
return true;
}
};
var image = new GUIImage(new RectTransform(Vector2.One, button.RectTransform), terminalButtonStyles[i], scaleToFit: true);
}
}
protected override void OnResolutionChanged()
{
base.OnResolutionChanged();
OnItemLoadedProjSpecific();
}
partial void OnItemLoadedProjSpecific()
{
Container.AllowUIOverlap = true;
Container.Inventory.RectTransform = containerHolder.RectTransform;
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
Write(msg, extraData);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), isServerMessage: true);
}
}
}
@@ -54,6 +54,11 @@ namespace Barotrauma.Items.Components
if (wireComponent != null)
{
equippedWire = wireComponent;
var connectedEnd = equippedWire.OtherConnection(null);
if (connectedEnd?.Item.Submarine != null && panel.Item.Submarine != connectedEnd.Item.Submarine)
{
equippedWire = null;
}
}
}
}
@@ -88,11 +88,6 @@ namespace Barotrauma.Items.Components
return character == Character.Controlled && character == user && character.SelectedConstruction == item;
}
public override void AddToGUIUpdateList()
{
GuiFrame?.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (character != Character.Controlled || character != user || character.SelectedConstruction != item) { return; }
@@ -63,11 +63,11 @@ namespace Barotrauma.Items.Components
}
OutputValue = input;
ShowOnDisplay(input);
ShowOnDisplay(input, addToHistory: true);
item.SendSignal(input, "signal_out");
}
partial void ShowOnDisplay(string input, bool addToHistory = true)
partial void ShowOnDisplay(string input, bool addToHistory)
{
if (addToHistory)
{
@@ -85,7 +85,7 @@ namespace Barotrauma.Items.Components
GUITextBlock newBlock = new GUITextBlock(
new RectTransform(new Vector2(1, 0), historyBox.Content.RectTransform, anchor: Anchor.TopCenter),
"> " + input,
textColor: Color.LimeGreen, wrap: true)
textColor: Color.LimeGreen, wrap: true, font: UseMonospaceFont ? GUI.MonospacedFont : GUI.GlobalFont)
{
CanBeFocused = false
};
@@ -118,9 +118,9 @@ namespace Barotrauma.Items.Components
// This method is overrided instead of the UpdateHUD method because this ensures the input box is selected
// even when the terminal component is selected for the very first time. Doing the input box selection in the
// UpdateHUD method only selects the input box on every terminal selection except for the very first time.
public override void AddToGUIUpdateList()
public override void AddToGUIUpdateList(int order = 0)
{
base.AddToGUIUpdateList();
base.AddToGUIUpdateList(order: order);
if (shouldSelectInputBox)
{
inputBox.Select();
@@ -39,6 +39,34 @@ namespace Barotrauma.Items.Components
private set;
}
[Serialize(false, false)]
public bool ThermalGoggles
{
get;
private set;
}
[Serialize(true, false)]
public bool ShowDeadCharacters
{
get;
private set;
}
[Serialize(true, false)]
public bool ShowTexts
{
get;
private set;
}
[Serialize("72,119,72,120", false)]
public Color OverlayColor
{
get;
private set;
}
private readonly List<Character> visibleCharacters = new List<Character>();
private const float UpdateInterval = 0.5f;
@@ -48,6 +76,8 @@ namespace Barotrauma.Items.Components
private bool isEquippable;
private float thermalEffectState;
public IEnumerable<Character> VisibleCharacters
{
get
@@ -80,7 +110,10 @@ namespace Barotrauma.Items.Components
{
refEntity = item;
}
thermalEffectState += deltaTime;
thermalEffectState %= 10000.0f;
if (updateTimer > 0.0f)
{
updateTimer -= deltaTime;
@@ -91,6 +124,7 @@ namespace Barotrauma.Items.Components
foreach (Character c in Character.CharacterList)
{
if (c == equipper || !c.Enabled || c.Removed) { continue; }
if (!ShowDeadCharacters && c.IsDead) { continue; }
float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.WorldPosition);
if (dist < Range * Range)
@@ -123,27 +157,71 @@ namespace Barotrauma.Items.Components
{
if (character == null) { return; }
GUI.UIGlow.Draw(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight),
Color.LightGreen * 0.5f);
Character closestCharacter = null;
float closestDist = float.PositiveInfinity;
foreach (Character c in visibleCharacters)
if (OverlayColor.A > 0)
{
if (c == character || !c.Enabled || c.Removed) { continue; }
float dist = Vector2.DistanceSquared(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), c.WorldPosition);
if (dist < closestDist)
{
closestCharacter = c;
closestDist = dist;
}
GUI.UIGlow.Draw(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), OverlayColor);
}
if (closestCharacter != null)
if (ShowTexts)
{
float dist = Vector2.Distance(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), closestCharacter.WorldPosition);
DrawCharacterInfo(spriteBatch, closestCharacter, 1.0f - MathHelper.Max((dist - (Range - FadeOutRange)) / FadeOutRange, 0.0f));
Character closestCharacter = null;
float closestDist = float.PositiveInfinity;
foreach (Character c in visibleCharacters)
{
if (c == character || !c.Enabled || c.Removed) { continue; }
float dist = Vector2.DistanceSquared(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), c.WorldPosition);
if (dist < closestDist)
{
closestCharacter = c;
closestDist = dist;
}
}
if (closestCharacter != null)
{
float dist = Vector2.Distance(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), closestCharacter.WorldPosition);
DrawCharacterInfo(spriteBatch, closestCharacter, 1.0f - MathHelper.Max((dist - (Range - FadeOutRange)) / FadeOutRange, 0.0f));
}
}
if (ThermalGoggles)
{
spriteBatch.End();
GameMain.LightManager.SolidColorEffect.Parameters["color"].SetValue(Color.Red.ToVector4() * (0.3f + MathF.Sin(thermalEffectState) * 0.05f));
GameMain.LightManager.SolidColorEffect.CurrentTechnique = GameMain.LightManager.SolidColorEffect.Techniques["SolidColorBlur"];
GameMain.LightManager.SolidColorEffect.Parameters["blurDistance"].SetValue(0.01f + MathF.Sin(thermalEffectState) * 0.005f);
GameMain.LightManager.SolidColorEffect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: Screen.Selected.Cam.Transform, effect: GameMain.LightManager.SolidColorEffect);
Entity refEntity = equipper;
if (!isEquippable || refEntity == null)
{
refEntity = item;
}
foreach (Character c in Character.CharacterList)
{
if (c == character || !c.Enabled || c.Removed || c.Params.HideInThermalGoggles) { continue; }
if (!ShowDeadCharacters && c.IsDead) { continue; }
float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.WorldPosition);
if (dist > Range * Range) { continue; }
Sprite pingCircle = GUI.Style.UIThermalGlow.Sprite;
foreach (Limb limb in c.AnimController.Limbs)
{
if (limb.Mass < 1.0f) { continue; }
float noise1 = PerlinNoise.GetPerlin((thermalEffectState + limb.Params.ID + c.ID) * 0.01f, (thermalEffectState + limb.Params.ID + c.ID) * 0.02f);
float noise2 = PerlinNoise.GetPerlin((thermalEffectState + limb.Params.ID + c.ID) * 0.01f, (thermalEffectState + limb.Params.ID + c.ID) * 0.008f);
Vector2 spriteScale = ConvertUnits.ToDisplayUnits(limb.body.GetSize()) / pingCircle.size * (noise1 * 0.5f + 2f);
Vector2 drawPos = new Vector2(limb.body.DrawPosition.X + (noise1 - 0.5f) * 100, -limb.body.DrawPosition.Y + (noise2 - 0.5f) * 100);
pingCircle.Draw(spriteBatch, drawPos, 0.0f, scale: Math.Max(spriteScale.X, spriteScale.Y));
}
}
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
}
}
@@ -177,6 +177,10 @@ namespace Barotrauma.Items.Components
partial void LaunchProjSpecific()
{
recoilTimer = RetractionTime;
if (user != null)
{
recoilTimer /= 1 + user.GetStatValue(StatTypes.TurretAttackSpeed);
}
PlaySound(ActionType.OnUse);
Vector2 particlePos = GetRelativeFiringPosition(UseFiringOffsetForMuzzleFlash);
foreach (ParticleEmitter emitter in particleEmitters)
@@ -534,20 +538,20 @@ namespace Barotrauma.Items.Components
minRotationWidget.Draw(spriteBatch, (float)Timing.Step);
maxRotationWidget.Draw(spriteBatch, (float)Timing.Step);
Vector2 GetDrawPos()
{
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
drawPos.Y = -drawPos.Y;
return drawPos;
}
void UpdateBarrel()
{
rotation = (minRotation + maxRotation) / 2;
}
}
public Vector2 GetDrawPos()
{
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
drawPos.Y = -drawPos.Y;
return drawPos;
}
private Widget GetWidget(string id, SpriteBatch spriteBatch, int size = 5, float thickness = 1f, Action<Widget> initMethod = null)
{
Vector2 offset = new Vector2(size / 2 + 5, -10);
@@ -5,17 +5,17 @@ namespace Barotrauma.Items.Components
{
partial class Wearable
{
private void GetDamageModifierText(ref string description, float damageMultiplier, string afflictionIdentifier)
private void GetDamageModifierText(ref string description, DamageModifier damageModifier, string afflictionIdentifier)
{
int roundedValue = (int)Math.Round((1 - damageMultiplier) * 100);
int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100);
if (roundedValue == 0) { return; }
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ?? afflictionIdentifier}";
}
public override void AddTooltipInfo(ref string description)
public override void AddTooltipInfo(ref string name, ref string description)
{
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f)) || SkillModifiers.Any())
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f) || !MathUtils.NearlyEqual(d.ProbabilityMultiplier, 1f)) || SkillModifiers.Any())
{
description += "\n";
}
@@ -31,11 +31,11 @@ namespace Barotrauma.Items.Components
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers)
{
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
}
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionTypes)
{
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
}
}
}
@@ -297,9 +297,10 @@ namespace Barotrauma
}
}
string name = item.Name;
foreach (ItemComponent component in item.Components)
{
component.AddTooltipInfo(ref description);
component.AddTooltipInfo(ref name, ref description);
}
if (item.Prefab.ShowContentsInTooltip && item.OwnInventory != null)
@@ -315,12 +316,18 @@ namespace Barotrauma
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
toolTip = $"‖color:{colorStr}‖{item.Name}‖color:end‖";
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
if (item.GetComponent<Quality>() != null)
{
// substring by to get rid of the empty space at start, text file should be adjusted
toolTip += $"\n{TextManager.GetWithVariable("itemname.quality" + item.Quality, "[itemname]", "", fallBackTag: "itemname.quality3")?.Substring(1)}";
}
if (itemsInSlot.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))
{
toolTip += " " + TextManager.Get("connectionlocked");
}
if (!item.IsFullCondition && !item.Prefab.HideConditionBar)
if (!item.IsFullCondition && !item.Prefab.HideConditionInTooltip)
{
string conditionColorStr = XMLExtensions.ColorToString(ToolBox.GradientLerp(item.Condition / item.MaxCondition, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull));
toolTip += $"‖color:{conditionColorStr}‖ ({(int)item.ConditionPercentage} %)‖color:end‖";
@@ -478,7 +485,7 @@ namespace Barotrauma
}
if (container == null) { return false; }
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
}
protected virtual bool HideSlot(int i)
@@ -594,7 +601,10 @@ namespace Barotrauma
{
var slotRef = new SlotReference(this, slot, slotIndex, isSubSlot, slots[slotIndex].FirstOrDefault()?.GetComponent<ItemContainer>()?.Inventory);
if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && slotRef.ParentInventory is CharacterInventory) { return; }
selectedSlot = slotRef;
if (CanSelectSlot(slotRef))
{
selectedSlot = slotRef;
}
}
if (!DraggingItems.Any())
@@ -667,6 +677,10 @@ namespace Barotrauma
if (subInventory.visualSlots == null) { subInventory.CreateSlots(); }
canMove = container.MovableFrame && !subInventory.IsInventoryHoverAvailable(Owner as Character, container) && subInventory.originalPos != Point.Zero;
if (this is CharacterInventory characterInventory && characterInventory.CurrentLayout != CharacterInventory.Layout.Default)
{
canMove = false;
}
if (canMove)
{
@@ -715,7 +729,7 @@ namespace Barotrauma
spacing = new Vector2(10 * UIScale, (10 + UnequippedIndicator.size.Y) * UIScale);
}
int columns = (int)Math.Max(Math.Floor(Math.Sqrt(itemCapacity)), 1);
int columns = MathHelper.Clamp((int)Math.Floor(Math.Sqrt(itemCapacity)), 1, container.SlotsPerRow);
while (itemCapacity / columns * (subRect.Height + spacing.Y) > GameMain.GraphicsHeight * 0.5f)
{
columns++;
@@ -826,11 +840,23 @@ namespace Barotrauma
return rect.Contains(PlayerInput.MousePosition);
}
public static bool IsMouseOnInventory
{
get; private set;
}
/// <summary>
/// Refresh the value of IsMouseOnInventory
/// </summary>
public static void RefreshMouseOnInventory()
{
IsMouseOnInventory = DetermineMouseOnInventory();
}
/// <summary>
/// Is the mouse on any inventory element (slot, equip button, subinventory...)
/// </summary>
/// <returns></returns>
public static bool IsMouseOnInventory(bool ignoreDraggedItem = false)
private static bool DetermineMouseOnInventory(bool ignoreDraggedItem = false)
{
if (GameMain.GameSession?.Campaign != null &&
(GameMain.GameSession.Campaign.ShowCampaignUI || GameMain.GameSession.Campaign.ForceMapUI))
@@ -1112,7 +1138,7 @@ namespace Barotrauma
{
Character.Controlled.ClearInputs();
if (!IsMouseOnInventory(ignoreDraggedItem: true) &&
if (!DetermineMouseOnInventory(ignoreDraggedItem: true) &&
CharacterHealth.OpenHealthWindow != null)
{
bool dropSuccessful = false;
@@ -1279,34 +1305,52 @@ namespace Barotrauma
DraggingItems.Clear();
}
if (selectedSlot != null)
if (selectedSlot != null && !CanSelectSlot(selectedSlot))
{
if (!selectedSlot.Slot.MouseOn())
selectedSlot = null;
}
}
private static bool CanSelectSlot(SlotReference selectedSlot)
{
if (!selectedSlot.Slot.MouseOn())
{
return false;
}
else
{
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
rootOwner != Character.Controlled &&
rootOwner != Character.Controlled.SelectedCharacter &&
rootOwner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
{
selectedSlot = null;
return false;
}
else
var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item;
if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) &&
ownerCharacter == Character.Controlled &&
CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface))
{
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
rootOwner != Character.Controlled &&
rootOwner != Character.Controlled.SelectedCharacter &&
rootOwner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
{
selectedSlot = null;
}
highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem);
return false;
}
}
return true;
}
protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
{
Rectangle hoverArea;
if (!subSlot.Inventory.Movable() || Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item))
if (!subSlot.Inventory.Movable() ||
(Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item)) ||
(subSlot.ParentInventory is CharacterInventory characterInventory && characterInventory.CurrentLayout != CharacterInventory.Layout.Default))
{
hoverArea = subSlot.Slot.Rect;
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
@@ -1375,7 +1419,7 @@ namespace Barotrauma
float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f);
Vector2 itemPos = PlayerInput.MousePosition;
bool mouseOnHealthInterface = CharacterHealth.OpenHealthWindow != null && CharacterHealth.OpenHealthWindow.MouseOnElement;
bool mouseOnHealthInterface = CharacterHealth.OpenHealthWindow != null && CharacterHealth.OpenHealthWindow.MouseOnElement && DraggingItems.Any(it => it.UseInHealthInterface);
if ((GUI.MouseOn == null || mouseOnHealthInterface) && selectedSlot == null)
{
@@ -1434,7 +1478,8 @@ namespace Barotrauma
}
Color slotColor = Color.White;
if (inventory?.Owner is Item i && !i.IsPlayerTeamInteractable) { slotColor = Color.Gray; }
Item parentItem = inventory?.Owner as Item;
if (parentItem != null && !parentItem.IsPlayerTeamInteractable) { slotColor = Color.Gray; }
var itemContainer = item?.GetComponent<ItemContainer>();
if (itemContainer != null && (itemContainer.InventoryTopSprite != null || itemContainer.InventoryBottomSprite != null))
{
@@ -1513,7 +1558,7 @@ namespace Barotrauma
var indicatorStyle = GUI.Style.GetComponentStyle("ContainedStateIndicator.Default");
Sprite indicatorSprite = indicatorStyle?.GetDefaultSprite();
Sprite emptyIndicatorSprite = indicatorStyle?.GetSprite(GUIComponent.ComponentState.Hover);
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
}
if (itemContainer != null && itemContainer.ShowContainedStateIndicator)
@@ -1525,14 +1570,14 @@ namespace Barotrauma
}
else
{
var containedItem = itemContainer.Inventory.slots[0].FirstOrDefault();
containedState = itemContainer.Inventory.Capacity == 1 ?
var containedItem = itemContainer.Inventory.slots[Math.Max(itemContainer.ContainedStateIndicatorSlot, 0)].FirstOrDefault();
containedState = itemContainer.Inventory.Capacity == 1 || itemContainer.ContainedStateIndicatorSlot > -1 ?
(containedItem == null ? 0.0f : containedItem.Condition / containedItem.MaxCondition) :
itemContainer.Inventory.slots.Count(i => !i.Empty()) / (float)itemContainer.Inventory.capacity;
if (containedItem != null && itemContainer.Inventory.Capacity == 1)
{
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.MaxStackSize);
if (maxStackSize > 1)
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.GetMaxStackSize(0));
if (maxStackSize > 1 || containedItem.Prefab.HideConditionBar)
{
containedState = itemContainer.Inventory.slots[0].ItemCount / (float)maxStackSize;
}
@@ -1556,6 +1601,27 @@ namespace Barotrauma
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, containedIndicatorArea, containedState,
pulsate: !usingDefaultSprite && containedState >= 0.0f && containedState < 0.25f && inventory == Character.Controlled?.Inventory && Character.Controlled.HasEquippedItem(item));
}
if (item.Quality != 0)
{
var style = GUI.Style.GetComponentStyle("InnerGlowSmall");
if (style == null)
{
GUI.DrawRectangle(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.7f);
}
else
{
style.Sprites[GUIComponent.ComponentState.None].FirstOrDefault()?.Draw(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.5f);
}
}
}
else
{
var slotIcon = parentItem?.GetComponent<ItemContainer>()?.GetSlotIcon(slotIndex);
if (slotIcon != null)
{
slotIcon.Draw(spriteBatch, rect.Center.ToVector2(), GUI.Style.EquipmentSlotIconColor, scale: Math.Min(rect.Width / slotIcon.size.X, rect.Height / slotIcon.size.Y) * 0.8f);
}
}
}
@@ -1590,7 +1656,7 @@ namespace Barotrauma
Color spriteColor = sprite == item.Sprite ? item.GetSpriteColor() : item.GetInventoryIconColor();
if (inventory != null && (inventory.Locked || inventory.slots[slotIndex].Items.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))) { spriteColor *= 0.5f; }
if (CharacterHealth.OpenHealthWindow != null && !item.UseInHealthInterface)
if (CharacterHealth.OpenHealthWindow != null && !item.UseInHealthInterface && !item.AllowedSlots.Contains(InvSlotType.HealthInterface) && item.GetComponent<GeneticMaterial>() == null)
{
spriteColor = Color.Lerp(spriteColor, Color.TransparentBlack, 0.5f);
}
@@ -1611,9 +1677,9 @@ namespace Barotrauma
scale: iconSize.X / stealIcon.size.X);
}
int maxStackSize = item.Prefab.MaxStackSize;
if (item.Container != null)
if (inventory is ItemInventory itemInventory)
{
maxStackSize = Math.Min(maxStackSize, item.Container.GetComponent<ItemContainer>()?.MaxStackSize ?? maxStackSize);
maxStackSize = Math.Min(maxStackSize, itemInventory.Container.GetMaxStackSize(slotIndex));
}
if (maxStackSize > 1 && inventory != null)
{
@@ -276,7 +276,7 @@ namespace Barotrauma
BrokenItemSprite fadeInBrokenSprite = null;
float fadeInBrokenSpriteAlpha = 0.0f;
float displayCondition = FakeBroken ? 0.0f : condition;
float displayCondition = FakeBroken ? 0.0f : ConditionPercentage;
Vector2 drawOffset = Vector2.Zero;
if (displayCondition < MaxCondition)
{
@@ -326,13 +326,18 @@ namespace Barotrauma
size, color: color,
textureScale: Vector2.One * Scale,
depth: depth);
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: depth - 0.000001f);
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 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);
}
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
decorativeSprite.Sprite.DrawTiled(spriteBatch,
@@ -357,7 +362,11 @@ namespace Barotrauma
if (color.A > 0)
{
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, d);
}
}
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
{
@@ -368,7 +377,7 @@ namespace Barotrauma
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
@@ -410,8 +419,11 @@ namespace Barotrauma
}
}
body.Draw(spriteBatch, activeSprite, color, depth, Scale);
if (fadeInBrokenSprite != null) { body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, depth - 0.000001f, Scale); }
if (fadeInBrokenSprite != null)
{
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, d, Scale);
}
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
@@ -464,6 +476,11 @@ namespace Barotrauma
if (GameMain.DebugDraw)
{
body?.DebugDraw(spriteBatch, Color.White);
if (GetComponent<TriggerComponent>()?.PhysicsBody is PhysicsBody triggerBody)
{
triggerBody.UpdateDrawPosition();
triggerBody.DebugDraw(spriteBatch, Color.White);
}
}
if (editing && IsSelected && PlayerInput.KeyDown(Keys.Space))
@@ -704,6 +721,7 @@ namespace Barotrauma
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"), style: "GUIButtonSmall")
{
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
Enabled = Prefab.CanFlipX,
OnClicked = (button, data) =>
{
foreach (MapEntity me in SelectedList)
@@ -717,6 +735,7 @@ namespace Barotrauma
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"), style: "GUIButtonSmall")
{
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
Enabled = Prefab.CanFlipY,
OnClicked = (button, data) =>
{
foreach (MapEntity me in SelectedList)
@@ -1068,7 +1087,7 @@ namespace Barotrauma
foreach (Character otherCharacter in Character.CharacterList)
{
if (otherCharacter != character &&
otherCharacter.SelectedConstruction == character.SelectedConstruction)
otherCharacter.SelectedConstruction == this)
{
ItemInUseWarning.Visible = true;
if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); }
@@ -1180,7 +1199,7 @@ namespace Barotrauma
return texts;
}
public override void AddToGUIUpdateList()
public override void AddToGUIUpdateList(int order = 0)
{
if (Screen.Selected is SubEditorScreen)
{
@@ -1194,7 +1213,14 @@ namespace Barotrauma
}
}
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this) { return; }
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this && GetComponent<RemoteController>() == null)
{
if (Character.Controlled.SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem != this &&
!Character.Controlled.HeldItems.Any(it => it.GetComponent<RemoteController>()?.TargetItem == this))
{
return;
}
}
bool needsLayoutUpdate = false;
foreach (ItemComponent ic in activeHUDs)
@@ -1205,7 +1231,7 @@ namespace Barotrauma
bool wasUsingAlternativeLayout = ic.UseAlternativeLayout;
ic.UseAlternativeLayout = useAlternativeLayout;
needsLayoutUpdate |= ic.UseAlternativeLayout != wasUsingAlternativeLayout;
ic.AddToGUIUpdateList();
ic.AddToGUIUpdateList(order);
}
if (itemInUseWarning != null && itemInUseWarning.Visible)
@@ -1530,6 +1556,7 @@ namespace Barotrauma
byte bodyType = msg.ReadByte();
bool spawnedInOutpost = msg.ReadBoolean();
bool allowStealing = msg.ReadBoolean();
int quality = msg.ReadRangedInteger(0, Items.Components.Quality.MaxQuality);
byte teamID = msg.ReadByte();
bool tagsChanged = msg.ReadBoolean();
string tags = "";
@@ -1605,7 +1632,8 @@ namespace Barotrauma
item = new Item(itemPrefab, pos, sub, id: itemId)
{
SpawnedInOutpost = spawnedInOutpost,
AllowStealing = allowStealing
AllowStealing = allowStealing,
Quality = quality
};
}
catch (Exception e)
@@ -1623,6 +1651,10 @@ namespace Barotrauma
{
wifiComponent.TeamID = (CharacterTeamType)teamID;
}
foreach (IdCard idCard in item.GetComponents<IdCard>())
{
idCard.TeamID = (CharacterTeamType)teamID;
}
if (descriptionChanged) { item.Description = itemDesc; }
if (tagsChanged) { item.Tags = tags; }
var nameTag = item.GetComponent<NameTag>();
@@ -77,6 +77,13 @@ namespace Barotrauma
protected set;
}
[Serialize(true, false)]
public bool ShowInStatusMonitor
{
get;
private set;
}
[Serialize("", false)]
public string ImpactSoundTag { get; private set; }
@@ -84,13 +91,13 @@ namespace Barotrauma
public override void UpdatePlacing(Camera cam)
{
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
if (PlayerInput.SecondaryMouseButtonClicked())
{
selected = null;
return;
}
var potentialContainer = MapEntity.GetPotentialContainer(position);
if (!ResizeHorizontal && !ResizeVertical)
@@ -155,7 +162,7 @@ namespace Barotrauma
{
potentialContainer.IsHighlighted = true;
}
//if (PlayerInput.GetMouseState.RightButton == ButtonState.Pressed) selected = null;