2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
5 using System.Collections.Generic;
10 partial class ItemContainer : ItemComponent, IDrawableComponent
12 private Sprite inventoryTopSprite;
13 private Sprite inventoryBackSprite;
14 private Sprite inventoryBottomSprite;
16 private GUICustomComponent guiCustomComponent;
21 private float[] containedSpriteDepths;
23 private Sprite[] slotIcons;
27 get {
return inventoryTopSprite; }
31 get {
return inventoryBackSprite; }
35 get {
return inventoryBottomSprite; }
55 [
Serialize(-1.0f,
IsPropertySaveable.No, description:
"Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.")]
66 [
Serialize(-1,
IsPropertySaveable.No, 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.")]
69 [
Serialize(
true,
IsPropertySaveable.No, description:
"Should an indicator displaying the state of the contained items be displayed on this item's inventory slot. "+
70 "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.")]
73 [
Serialize(
false,
IsPropertySaveable.No, description:
"If enabled, the condition of this item is displayed in the indicator that would normally show the state of the contained items." +
74 " May be useful for items such as ammo boxes and magazines that spawn projectiles as needed," +
75 " and use the condition to determine how many projectiles can be spawned in total.")]
82 [
Serialize(
false,
IsPropertySaveable.No, description:
"If true, the contained state indicator calculates how full the item is based on the total amount of items that can be stacked inside it, as opposed to how many of the inventory slots are occupied." +
83 " Note that only items in the main container or in the subcontainer are counted, depending on which container the first containable item match is found in. The item determining this can be defined with ContainedStateIndicatorSlot")]
86 [
Serialize(
false,
IsPropertySaveable.No, description:
"Should the inventory of this item be kept open when the item is equipped by a character.")]
89 [
Serialize(
false,
IsPropertySaveable.No, description:
"Can the inventory of this item be moved around on the screen by the player.")]
95 get {
return Vector2.Zero; }
100 slotIcons =
new Sprite[capacity];
103 foreach (var subElement
in element.
Elements())
105 switch (subElement.Name.ToString().ToLowerInvariant())
108 inventoryTopSprite =
new Sprite(subElement);
111 inventoryBackSprite =
new Sprite(subElement);
114 inventoryBottomSprite =
new Sprite(subElement);
116 case "containedstateindicator":
119 case "containedstateindicatorempty":
123 int index = subElement.GetAttributeInt(
"slotindex", -1);
125 for (
int i = 0; i < capacity; i++)
127 if (i == index || index == -1)
134 int subContainerCapacity = subElement.GetAttributeInt(
"capacity", 1);
135 var slotIconElement = subElement.GetChildElement(
"sloticon");
136 if (slotIconElement !=
null)
138 var slotIcon =
new Sprite(slotIconElement);
139 for (
int i = currCapacity; i < currCapacity + subContainerCapacity; i++)
141 slotIcons[i] = slotIcon;
144 currCapacity += subContainerCapacity;
154 IndicatorStyle = GUIStyle.GetComponentStyle(
"ContainedStateIndicator.Default");
162 DebugConsole.AddWarning($
"Item \"{item.Name}\" defines both a contained state indicator style and a custom indicator sprite. Will use the custom sprite...",
170 GuiFrame =
new GUIFrame(
new RectTransform(Vector2.One, GUI.Canvas), style:
null)
175 onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
201 labelText, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft, wrap:
true)
203 IgnoreLayoutGroups =
true
206 int buttonSize = GUIStyle.ItemFrameTopBarHeight;
207 Point margin =
new Point(buttonSize / 4, buttonSize / 6);
210 isHorizontal:
true, childAnchor:
Anchor.TopRight)
212 AbsoluteSpacing = margin.X / 2
218 ToolTip = TextManager.Get(
"SortItemsAlphabetically"),
219 OnClicked = (btn, userdata) =>
227 ToolTip = TextManager.Get(
"MergeItemStacks"),
228 OnClicked = (btn, userdata) =>
236 float minInventoryAreaSize = 0.5f;
239 onDraw: (SpriteBatch spriteBatch,
GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
252 newMaxSize.Y = newHeight;
256 content.RectTransform.Resize(
GuiFrame.
Rect.Size - GUIStyle.ItemFrameMargin);
258 guiCustomComponent.RectTransform.Resize(
new Vector2(1.0f, Math.Max(1.0f - label.
RectTransform.
RelativeSize.Y, minInventoryAreaSize)));
264 private void SortItems()
266 List<List<Item>> itemsPerSlot =
new List<List<Item>>();
273 itemsPerSlot.Add(items);
274 items.ForEach(it => it.Drop(dropper:
null, createNetworkEvent:
false, setTransform:
false));
278 var sortedItems = itemsPerSlot
279 .OrderBy(i => i.First().Name)
281 .ThenByDescending(i => i.Count)
283 .ThenByDescending(i => i.First().ContainedItems.Count());
285 foreach (var items
in sortedItems)
287 int firstFreeSlot = -1;
296 if (firstFreeSlot == -1)
298 items.ForEach(it => it.Drop(dropper:
null));
301 foreach (var
item in items)
303 if (!
Inventory.
TryPutItem(
item, firstFreeSlot, allowSwapping:
false, allowCombine:
false, user:
null, createNetworkEvent:
false))
316 private void MergeStacks()
321 if (items.None()) {
continue; }
323 for (
int j = 0; j < i; j++)
327 items.ForEach(it =>
Inventory.
TryPutItem(it, j, allowSwapping:
false, allowCombine:
false, user:
null, createNetworkEvent:
false));
337 if (
UILabel ==
string.Empty) {
return string.Empty; }
350 if (slotIndex < 0 || slotIndex >= slotIcons.Length) {
return null; }
351 return slotIcons[slotIndex];
384 if (containedItems ==
null) {
return 0.0f; }
386 Item containedItem = containedItems.FirstOrDefault();
391 containedItems.FirstOrDefault() ??
393 if (containedItem ==
null) {
return 0.0f; }
395 int ignoredItemCount = 0;
399 if (subContainableItems !=
null)
401 bool useMainContainerCapacity =
true;
410 useMainContainerCapacity =
false;
418 if (!useMainContainerCapacity) {
break; }
420 if (!useMainContainerCapacity)
428 return Math.Min(itemCount / Math.Max(capacity, 1), 1);
434 if (containedItem ==
null) {
return 0.0f; }
438 return containedItemContainer.GetContainedIndicatorState();
441 if (maxStackSize == 1)
445 return containedItems.Count() / (float)maxStackSize;
453 public void Draw(SpriteBatch spriteBatch,
bool editing =
false,
float itemDepth = -1, Color? overrideColor =
null)
459 public void DrawContainedItems(SpriteBatch spriteBatch,
float itemDepth, Color? overrideColor =
null)
463 Vector2 transformedItemIntervalHorizontal =
new Vector2(transformedItemInterval.X, 0.0f);
464 Vector2 transformedItemIntervalVertical =
new Vector2(0.0f, transformedItemInterval.Y);
470 transformedItemPos.X = -transformedItemPos.X;
471 transformedItemPos.X +=
item.
Rect.Width;
472 transformedItemInterval.X = -transformedItemInterval.X;
473 transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
477 transformedItemPos.Y = -transformedItemPos.Y;
478 transformedItemPos.Y -=
item.
Rect.Height;
479 transformedItemInterval.Y = -transformedItemInterval.Y;
480 transformedItemIntervalVertical.Y = -transformedItemIntervalVertical.Y;
489 transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
490 transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
491 transformedItemIntervalVertical = Vector2.Transform(transformedItemIntervalVertical, transform);
499 transformedItemPos.X = -transformedItemPos.X;
500 transformedItemInterval.X = -transformedItemInterval.X;
501 transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
504 transformedItemPos = Vector2.Transform(transformedItemPos, transform);
505 transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
506 transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
510 Vector2 currentItemPos = transformedItemPos;
515 foreach (ContainedItem contained
in containedItems)
517 Vector2 itemPos = currentItemPos;
519 if (contained.Item?.Sprite ==
null) {
continue; }
521 if (contained.Hide) {
continue; }
522 if (contained.ItemPos.HasValue)
524 Vector2 pos = contained.ItemPos.Value;
537 itemPos.X = -itemPos.X;
542 itemPos.Y = -itemPos.Y;
564 Vector2 origin = contained.Item.Sprite.Origin;
565 if (
item.
FlippedX) { origin.X = contained.Item.Sprite.SourceRect.Width - origin.X; }
566 if (
item.
FlippedY) { origin.Y = contained.Item.Sprite.SourceRect.Height - origin.Y; }
569 if (i < containedSpriteDepths.Length)
571 containedSpriteDepth = containedSpriteDepths[i];
575 SpriteEffects spriteEffects = SpriteEffects.None;
577 if (contained.Rotation != 0)
579 spriteRotation = contained.Rotation;
584 spriteEffects |= MathUtils.NearlyEqual(spriteRotation % 180, 90.0f) ? SpriteEffects.FlipVertically : SpriteEffects.FlipHorizontally;
589 spriteEffects |= MathUtils.NearlyEqual(spriteRotation % 180, 90.0f) ? SpriteEffects.FlipHorizontally : SpriteEffects.FlipVertically;
592 contained.Item.Sprite.Draw(
594 new Vector2(itemPos.X, -itemPos.Y),
595 overrideColor ?? (isWiringMode ? contained.Item.GetSpriteColor(withHighlight:
true) * 0.15f : contained.Item.GetSpriteColor(withHighlight:
true)),
597 -(contained.Item.body ==
null ? 0.0f : contained.Item.body.DrawRotation),
598 contained.Item.Scale,
600 depth: containedSpriteDepth);
601 contained.Item.DrawDecorativeSprites(spriteBatch, itemPos, flipX,flipY, (contained.Item.body ==
null ? 0.0f : contained.Item.body.DrawRotation),
602 containedSpriteDepth, overrideColor);
606 if (ic.hideItems) {
continue; }
607 ic.DrawContainedItems(spriteBatch, containedSpriteDepth, overrideColor);
614 currentItemPos += transformedItemIntervalHorizontal;
617 currentItemPos = transformedItemPos;
618 currentItemPos += transformedItemIntervalVertical * (i /
ItemsPerRow);
623 currentItemPos += transformedItemInterval;
644 if (!guiCustomComponent.Visible) {
return; }
bool HasEquippedItem(Item item, InvSlotType? slotType=null, Func< InvSlotType, bool > predicate=null)
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
bool CanAccessInventory(Inventory inventory, CharacterInventory.AccessLevel accessLevel=CharacterInventory.AccessLevel.Limited)
IEnumerable< Item >?? HeldItems
Items the character has in their hand slots. Doesn't return nulls and only returns items held in both...
float?[] GetAttributeFloatArray(string key, float[]? def)
IEnumerable< ContentXElement > Elements()
virtual Vector2 DrawPosition
RectTransform RectTransform
GUIComponent that can be used to render custom content on the UI
void CalculateHeightFromText(int padding=0, bool removeExtraSpacing=false)
virtual void Update(float deltaTime, Camera cam, bool subInventory=false)
bool DrawWhenEquipped
Normally false - we don't draw the UI because it's drawn when the player hovers the cursor over the i...
RectTransform RectTransform
If set, the inventory is automatically positioned inside the rect
virtual IEnumerable< Item > AllItems
All items contained in the inventory. Stacked items are returned as individual instances....
IEnumerable< Item > GetItemsAt(int index)
Get all the item stored in the specified inventory slot. Can return more than one item if the slot co...
Item GetItemAt(int index)
Get the item stored in the specified inventory slot. If the slot contains a stack of items,...
bool CanBePut(Item item)
Can the item be put in the inventory (i.e. is there a suitable free slot or a stack the item can be p...
void Drop(Character dropper, bool createNetworkEvent=true, bool setTransform=true)
Inventory ParentInventory
bool IsInteractable(Character character)
Returns interactibility based on whether the character is on a player team
override bool TryPutItem(Item item, Character user, IEnumerable< InvSlotType > allowedSlots=null, bool createNetworkEvent=true, bool ignoreCondition=false)
If there is room, puts the item in the inventory and returns true, otherwise returns false
override bool CanBePutInSlot(Item item, int i, bool ignoreCondition=false)
Can the item be put in the specified slot.
override void CreateNetworkEvent(Range slotRange)
int GetMaxStackSize(Inventory inventory)
override LocalizedString Name
void OnGUIParentChanged(RectTransform newParent)
Launches when the parent of the GuiFrame is changed.
GUIComponentStyle IndicatorStyle
Sprite ContainedStateIndicatorEmpty
Sprite ContainedStateIndicator
readonly ItemInventory Inventory
float ContainedSpriteDepth
Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is...
bool KeepOpenWhenEquipped
Sprite GetSlotIcon(int slotIndex)
bool ShowConditionInContainedStateIndicator
LocalizedString GetUILabel()
bool CanBeContained(Item item)
bool AutoInteractWithContained
override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
override bool RecreateGUIOnResolutionChange
bool ShowTotalStackCapacityInContainedStateIndicator
float GetContainedIndicatorState()
int ContainedStateIndicatorSlot
Sprite InventoryBottomSprite
bool ShowContainedStateIndicator
Sprite InventoryTopSprite
List< RelatedItem > AllSubContainableItems
string ContainedStateIndicatorStyle
int GetMaxStackSize(int slotIndex)
void DrawContainedItems(SpriteBatch spriteBatch, float itemDepth, Color? overrideColor=null)
void Draw(SpriteBatch spriteBatch, bool editing=false, float itemDepth=-1, Color? overrideColor=null)
override void CreateGUI()
Overload this method and implement. The method is automatically called when the resolution changes.
int MainContainerCapacity
The capacity of the main container without taking the sub containers into account....
Sprite InventoryBackSprite
bool KeepOpenWhenEquippedBy(Character character)
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
ContentPackage? ContentPackage
static bool IsWiringMode()
static bool TransparentWiringMode