Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs
2020-07-30 13:00:09 +03:00

290 lines
12 KiB
C#

using System;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
partial class ItemContainer : ItemComponent, IDrawableComponent
{
private Sprite inventoryTopSprite;
private Sprite inventoryBackSprite;
private Sprite inventoryBottomSprite;
private GUICustomComponent guiCustomComponent;
public Sprite InventoryTopSprite
{
get { return inventoryTopSprite; }
}
public Sprite InventoryBackSprite
{
get { return inventoryBackSprite; }
}
public Sprite InventoryBottomSprite
{
get { return inventoryBottomSprite; }
}
public Sprite ContainedStateIndicator
{
get;
private set;
}
#if DEBUG
[Editable]
#endif
[Serialize("0.0,0.0", false, description: "The position where the contained items get drawn at (offset from the upper left corner of the sprite in pixels).")]
public Vector2 ItemPos { get; set; }
#if DEBUG
[Editable]
#endif
[Serialize("0.0,0.0", false, description: "The interval at which the contained items are spaced apart from each other (in pixels).")]
public Vector2 ItemInterval { get; set; }
[Serialize(100, false, description: "How many items are placed in a row before starting a new row.")]
public int ItemsPerRow { get; set; }
/// <summary>
/// Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.
/// </summary>
[Serialize(-1.0f, false, description: "Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.")]
public float ContainedSpriteDepth { get; set; }
[Serialize(null, false, description: "An optional text displayed above the item's inventory.")]
public string UILabel { 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; }
[Serialize(false, false, description: "If enabled, the condition of this item is displayed in the indicator that would normally show the state of the contained items." +
" May be useful for items such as ammo boxes and magazines that spawn projectiles as needed," +
" and use the condition to determine how many projectiles can be spawned in total.")]
public bool ShowConditionInContainedStateIndicator
{
get;
set;
}
[Serialize(false, false, description: "Should the inventory of this item be kept open when the item is equipped by a character.")]
public bool KeepOpenWhenEquipped { get; set; }
[Serialize(false, false, description: "Can the inventory of this item be moved around on the screen by the player.")]
public bool MovableFrame { get; set; }
public Vector2 DrawSize
{
//use the extents of the item as the draw size
get { return Vector2.Zero; }
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "topsprite":
inventoryTopSprite = new Sprite(subElement);
break;
case "backsprite":
inventoryBackSprite = new Sprite(subElement);
break;
case "bottomsprite":
inventoryBottomSprite = new Sprite(subElement);
break;
case "containedstateindicator":
ContainedStateIndicator = new Sprite(subElement);
break;
}
}
if (GuiFrame == null)
{
//if a GUIFrame is not defined in the xml,
//we create a full-screen frame and let the inventory position itself on it
GuiFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
{
CanBeFocused = false
};
guiCustomComponent = new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform),
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
};
GuiFrame.RectTransform.ParentChanged += OnGUIParentChanged;
}
else
{
//if a GUIFrame has been defined, draw the inventory inside it
CreateGUI();
}
}
protected override void CreateGUI()
{
var content = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset },
style: null)
{
CanBeFocused = false
};
string labelText = GetUILabel();
GUITextBlock label = null;
if (!string.IsNullOrEmpty(labelText))
{
label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform, Anchor.TopCenter),
labelText, font: GUI.SubHeadingFont, textAlignment: Alignment.Center, wrap: true);
}
float minInventoryAreaSize = 0.5f;
guiCustomComponent = new GUICustomComponent(
new RectTransform(new Vector2(1.0f, label == null ? 1.0f : Math.Max(1.0f - label.RectTransform.RelativeSize.Y, minInventoryAreaSize)), content.RectTransform, Anchor.BottomCenter),
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
};
Inventory.RectTransform = guiCustomComponent.RectTransform;
}
public string GetUILabel()
{
if (UILabel == string.Empty) { return string.Empty; }
if (UILabel != null)
{
return TextManager.Get("UILabel." + UILabel);
}
else
{
return item?.Name;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
DrawContainedItems(spriteBatch, itemDepth);
}
public void DrawContainedItems(SpriteBatch spriteBatch, float itemDepth)
{
Vector2 transformedItemPos = ItemPos * item.Scale;
Vector2 transformedItemInterval = ItemInterval * item.Scale;
if (item.body == null)
{
if (item.FlippedX)
{
transformedItemPos.X = -transformedItemPos.X;
transformedItemPos.X += item.Rect.Width;
transformedItemInterval.X = -transformedItemInterval.X;
}
if (item.FlippedY)
{
transformedItemPos.Y = -transformedItemPos.Y;
transformedItemPos.Y -= item.Rect.Height;
transformedItemInterval.Y = -transformedItemInterval.Y;
}
transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; }
}
else
{
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
if (item.body.Dir == -1.0f)
{
transformedItemPos.X = -transformedItemPos.X;
transformedItemInterval.X = -transformedItemInterval.X;
}
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
transformedItemPos += item.DrawPosition;
}
Vector2 currentItemPos = transformedItemPos;
SpriteEffects spriteEffects = SpriteEffects.None;
if ((item.body != null && item.body.Dir == -1) || item.FlippedX) { spriteEffects |= SpriteEffects.FlipHorizontally; }
if (item.FlippedY) { spriteEffects |= SpriteEffects.FlipVertically; }
int i = 0;
foreach (Item containedItem in Inventory.Items)
{
if (containedItem == null) continue;
if (AutoInteractWithContained)
{
containedItem.IsHighlighted = item.IsHighlighted;
item.IsHighlighted = false;
}
Vector2 origin = containedItem.Sprite.Origin;
if (item.FlippedX) { origin.X = containedItem.Sprite.SourceRect.Width - origin.X; }
if (item.FlippedY) { origin.Y = containedItem.Sprite.SourceRect.Height - origin.Y; }
float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth;
containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f;
containedItem.Sprite.Draw(
spriteBatch,
new Vector2(currentItemPos.X, -currentItemPos.Y),
containedItem.GetSpriteColor(),
origin,
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation),
containedItem.Scale,
spriteEffects,
depth: containedSpriteDepth);
foreach (ItemContainer ic in containedItem.GetComponents<ItemContainer>())
{
if (ic.hideItems) continue;
ic.DrawContainedItems(spriteBatch, containedSpriteDepth);
}
i++;
if (Math.Abs(ItemInterval.X) > 0.001f && Math.Abs(ItemInterval.Y) > 0.001f)
{
//interval set on both axes -> use a grid layout
currentItemPos.X += transformedItemInterval.X;
if (i % ItemsPerRow == 0)
{
currentItemPos.X = transformedItemPos.X;
currentItemPos.Y += transformedItemInterval.Y;
}
}
else
{
currentItemPos += transformedItemInterval;
}
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (Inventory.RectTransform != null)
{
guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;
}
//if the item is in the character's inventory, no need to update the item's inventory
//because the player can see it by hovering the cursor over the item
guiCustomComponent.Visible = item.ParentInventory?.Owner != character && DrawInventory;
if (!guiCustomComponent.Visible) return;
Inventory.Update(deltaTime, cam);
}
/*public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
//if the item is in the character's inventory, no need to draw the item's inventory
//because the player can see it by hovering the cursor over the item
if (item.ParentInventory?.Owner == character || !DrawInventory) return;
Inventory.Draw(spriteBatch);
}*/
}
}