Client LuaCsForBarotrauma
BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs
2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 
9 {
10  partial class ItemContainer : ItemComponent, IDrawableComponent
11  {
12  private Sprite inventoryTopSprite;
13  private Sprite inventoryBackSprite;
14  private Sprite inventoryBottomSprite;
15 
16  private GUICustomComponent guiCustomComponent;
17 
21  private float[] containedSpriteDepths;
22 
23  private Sprite[] slotIcons;
24 
26  {
27  get { return inventoryTopSprite; }
28  }
30  {
31  get { return inventoryBackSprite; }
32  }
34  {
35  get { return inventoryBottomSprite; }
36  }
37 
39  {
40  get;
41  private set;
42  }
43 
45  {
46  get;
47  private set;
48  }
49 
50  public override bool RecreateGUIOnResolutionChange => true;
51 
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.")]
56  public float ContainedSpriteDepth { get; set; }
57 
58  [Serialize(null, IsPropertySaveable.No, description: "An optional text displayed above the item's inventory.")]
59  public string UILabel { get; set; }
60 
61  public GUIComponentStyle IndicatorStyle { get; set; }
62 
63  [Serialize(null, IsPropertySaveable.No)]
64  public string ContainedStateIndicatorStyle { get; set; }
65 
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.")]
67  public int ContainedStateIndicatorSlot { get; set; }
68 
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.")]
71  public bool ShowContainedStateIndicator { get; set; }
72 
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.")]
77  {
78  get;
79  set;
80  }
81 
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")]
85 
86  [Serialize(false, IsPropertySaveable.No, description: "Should the inventory of this item be kept open when the item is equipped by a character.")]
87  public bool KeepOpenWhenEquipped { get; set; }
88 
89  [Serialize(false, IsPropertySaveable.No, description: "Can the inventory of this item be moved around on the screen by the player.")]
90  public bool MovableFrame { get; set; }
91 
92  public Vector2 DrawSize
93  {
94  //use the extents of the item as the draw size
95  get { return Vector2.Zero; }
96  }
97 
98  partial void InitProjSpecific(ContentXElement element)
99  {
100  slotIcons = new Sprite[capacity];
101 
102  int currCapacity = MainContainerCapacity;
103  foreach (var subElement in element.Elements())
104  {
105  switch (subElement.Name.ToString().ToLowerInvariant())
106  {
107  case "topsprite":
108  inventoryTopSprite = new Sprite(subElement);
109  break;
110  case "backsprite":
111  inventoryBackSprite = new Sprite(subElement);
112  break;
113  case "bottomsprite":
114  inventoryBottomSprite = new Sprite(subElement);
115  break;
116  case "containedstateindicator":
117  ContainedStateIndicator = new Sprite(subElement);
118  break;
119  case "containedstateindicatorempty":
120  ContainedStateIndicatorEmpty = new Sprite(subElement);
121  break;
122  case "sloticon":
123  int index = subElement.GetAttributeInt("slotindex", -1);
124  Sprite icon = new Sprite(subElement);
125  for (int i = 0; i < capacity; i++)
126  {
127  if (i == index || index == -1)
128  {
129  slotIcons[i] = icon;
130  }
131  }
132  break;
133  case "subcontainer":
134  int subContainerCapacity = subElement.GetAttributeInt("capacity", 1);
135  var slotIconElement = subElement.GetChildElement("sloticon");
136  if (slotIconElement != null)
137  {
138  var slotIcon = new Sprite(slotIconElement);
139  for (int i = currCapacity; i < currCapacity + subContainerCapacity; i++)
140  {
141  slotIcons[i] = slotIcon;
142  }
143  }
144  currCapacity += subContainerCapacity;
145  break;
146  }
147  }
148 
149  if (string.IsNullOrEmpty(ContainedStateIndicatorStyle))
150  {
151  //if neither a style or a custom sprite is defined, use default style
152  if (ContainedStateIndicator == null)
153  {
154  IndicatorStyle = GUIStyle.GetComponentStyle("ContainedStateIndicator.Default");
155  }
156  }
157  else
158  {
159  IndicatorStyle = GUIStyle.GetComponentStyle("ContainedStateIndicator." + ContainedStateIndicatorStyle);
161  {
162  DebugConsole.AddWarning($"Item \"{item.Name}\" defines both a contained state indicator style and a custom indicator sprite. Will use the custom sprite...",
163  contentPackage: item.Prefab.ContentPackage);
164  }
165  }
166  if (GuiFrame == null)
167  {
168  //if a GUIFrame is not defined in the xml,
169  //we create a full-screen frame and let the inventory position itself on it
170  GuiFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
171  {
172  CanBeFocused = false
173  };
174  guiCustomComponent = new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform),
175  onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
176  onUpdate: null)
177  {
178  CanBeFocused = false
179  };
181  }
182  else
183  {
184  //if a GUIFrame has been defined, draw the inventory inside it
185  CreateGUI();
186  }
187 
188  containedSpriteDepths = element.GetAttributeFloatArray("containedspritedepths", Array.Empty<float>());
189  }
190 
191  protected override void CreateGUI()
192  {
193  var content = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset },
194  style: null)
195  {
196  CanBeFocused = false
197  };
198 
199  LocalizedString labelText = GetUILabel();
200  GUITextBlock label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform, Anchor.TopCenter),
201  labelText, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft, wrap: true)
202  {
203  IgnoreLayoutGroups = true
204  };
205 
206  int buttonSize = GUIStyle.ItemFrameTopBarHeight;
207  Point margin = new Point(buttonSize / 4, buttonSize / 6);
208 
209  GUILayoutGroup buttonArea = new GUILayoutGroup(new RectTransform(new Point(content.Rect.Width, buttonSize - margin.Y * 2), content.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(0, margin.Y) },
210  isHorizontal: true, childAnchor: Anchor.TopRight)
211  {
212  AbsoluteSpacing = margin.X / 2
213  };
214  if (Inventory.Capacity > 1)
215  {
216  new GUIButton(new RectTransform(Vector2.One, buttonArea.RectTransform, scaleBasis: ScaleBasis.Smallest), style: "SortItemsButton")
217  {
218  ToolTip = TextManager.Get("SortItemsAlphabetically"),
219  OnClicked = (btn, userdata) =>
220  {
221  SortItems();
222  return true;
223  }
224  };
225  new GUIButton(new RectTransform(Vector2.One, buttonArea.RectTransform, scaleBasis: ScaleBasis.Smallest), style: "MergeStacksButton")
226  {
227  ToolTip = TextManager.Get("MergeItemStacks"),
228  OnClicked = (btn, userdata) =>
229  {
230  MergeStacks();
231  return true;
232  }
233  };
234  }
235 
236  float minInventoryAreaSize = 0.5f;
237  guiCustomComponent = new GUICustomComponent(
238  new RectTransform(new Vector2(1.0f, label == null ? 1.0f : Math.Max(1.0f - label.RectTransform.RelativeSize.Y, minInventoryAreaSize)), content.RectTransform, Anchor.BottomCenter),
239  onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
240  onUpdate: null)
241  {
242  CanBeFocused = true
243  };
244 
245  // Expand the frame vertically if it's too small to fit the text
246  if (label != null && label.RectTransform.RelativeSize.Y > 0.5f)
247  {
248  int newHeight = (int)(GuiFrame.Rect.Height + (2 * (label.RectTransform.RelativeSize.Y - 0.5f) * content.Rect.Height));
249  if (newHeight > GuiFrame.RectTransform.MaxSize.Y)
250  {
251  Point newMaxSize = GuiFrame.RectTransform.MaxSize;
252  newMaxSize.Y = newHeight;
253  GuiFrame.RectTransform.MaxSize = newMaxSize;
254  }
255  GuiFrame.RectTransform.Resize(new Point(GuiFrame.Rect.Width, newHeight));
256  content.RectTransform.Resize(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin);
257  label.CalculateHeightFromText();
258  guiCustomComponent.RectTransform.Resize(new Vector2(1.0f, Math.Max(1.0f - label.RectTransform.RelativeSize.Y, minInventoryAreaSize)));
259  }
260 
261  Inventory.RectTransform = guiCustomComponent.RectTransform;
262  }
263 
264  private void SortItems()
265  {
266  List<List<Item>> itemsPerSlot = new List<List<Item>>();
267 
268  for (int i = 0; i < Inventory.Capacity; i++)
269  {
270  var items = Inventory.GetItemsAt(i).ToList();
271  if (items.Any())
272  {
273  itemsPerSlot.Add(items);
274  items.ForEach(it => it.Drop(dropper: null, createNetworkEvent: false, setTransform: false));
275  }
276  }
277 
278  var sortedItems = itemsPerSlot
279  .OrderBy(i => i.First().Name)
280  //if there's multiple items with the same name, sort largest stacks first
281  .ThenByDescending(i => i.Count)
282  //same name and stack size, sort items with most items inside first
283  .ThenByDescending(i => i.First().ContainedItems.Count());
284 
285  foreach (var items in sortedItems)
286  {
287  int firstFreeSlot = -1;
288  for (int i = 0; i < Inventory.Capacity; i++)
289  {
290  if (Inventory.GetItemAt(i) == null && Inventory.CanBePut(items.First()))
291  {
292  firstFreeSlot = i;
293  break;
294  }
295  }
296  if (firstFreeSlot == -1)
297  {
298  items.ForEach(it => it.Drop(dropper: null));
299  continue;
300  }
301  foreach (var item in items)
302  {
303  if (!Inventory.TryPutItem(item, firstFreeSlot, allowSwapping: false, allowCombine: false, user: null, createNetworkEvent: false))
304  {
305  //if putting in the specific slot fails (prevented by containable restrictions?), just put in the first free slot
306  if (!Inventory.TryPutItem(item, user: null, createNetworkEvent: false))
307  {
308  item.Drop(dropper: null);
309  }
310  }
311  }
312  }
314  }
315 
316  private void MergeStacks()
317  {
318  for (int i = Inventory.Capacity - 1; i >= 0; i--)
319  {
320  var items = Inventory.GetItemsAt(i).ToList();
321  if (items.None()) { continue; }
322  //find the first stack we can put the item in
323  for (int j = 0; j < i; j++)
324  {
325  if (Inventory.GetItemsAt(j).Any() && Inventory.CanBePutInSlot(items.First(), j))
326  {
327  items.ForEach(it => Inventory.TryPutItem(it, j, allowSwapping: false, allowCombine: false, user: null, createNetworkEvent: false));
328  break;
329  }
330  }
331  }
333  }
334 
336  {
337  if (UILabel == string.Empty) { return string.Empty; }
338  if (UILabel != null)
339  {
340  return TextManager.Get("UILabel." + UILabel).Fallback(TextManager.Get(UILabel));
341  }
342  else
343  {
344  return item?.Prefab.Name;
345  }
346  }
347 
348  public Sprite GetSlotIcon(int slotIndex)
349  {
350  if (slotIndex < 0 || slotIndex >= slotIcons.Length) { return null; }
351  return slotIcons[slotIndex];
352  }
353 
354  public bool KeepOpenWhenEquippedBy(Character character)
355  {
356  if (!KeepOpenWhenEquipped ||
357  !character.HasEquippedItem(Item) ||
358  !character.CanAccessInventory(Inventory))
359  {
360  return false;
361  }
362 
363  //if holding 2 different "always open" items in different hands, don't force them to stay open
364  if (character.HeldItems.Count() > 1 && character.HeldItems.All(it => it.GetComponent<ItemContainer>()?.KeepOpenWhenEquipped ?? false))
365  {
366  return false;
367  }
368 
369  return true;
370  }
371 
372 
374  {
376  {
377  return item.Condition / item.MaxCondition;
378  }
379 
380  int targetSlot = Math.Max(ContainedStateIndicatorSlot, 0);
381  if (targetSlot >= Inventory.Capacity) { return 0.0f; }
382 
383  var containedItems = Inventory.GetItemsAt(targetSlot);
384  if (containedItems == null) { return 0.0f; }
385 
386  Item containedItem = containedItems.FirstOrDefault();
388  {
389  // No item on the defined slot, check if the items on other slots can be used.
390  containedItem ??=
391  containedItems.FirstOrDefault() ??
392  Inventory.AllItems.FirstOrDefault(it => CanBeContained(it, targetSlot));
393  if (containedItem == null) { return 0.0f; }
394 
395  int ignoredItemCount = 0;
396  var subContainableItems = AllSubContainableItems;
397  float targetSlotCapacity = Math.Min(containedItem.Prefab.MaxStackSize, GetMaxStackSize(targetSlot));
398  float capacity = targetSlotCapacity * MainContainerCapacity;
399  if (subContainableItems != null)
400  {
401  bool useMainContainerCapacity = true;
402  foreach (Item it in Inventory.AllItems)
403  {
404  // Ignore all items in the sub containers.
405  foreach (RelatedItem ri in subContainableItems)
406  {
407  if (ri.MatchesItem(containedItem))
408  {
409  // The target item is in a subcontainer -> inverse the logic.
410  useMainContainerCapacity = false;
411  break;
412  }
413  if (ri.MatchesItem(it))
414  {
415  ignoredItemCount++;
416  }
417  }
418  if (!useMainContainerCapacity) { break; }
419  }
420  if (!useMainContainerCapacity)
421  {
422  // Ignore all items in the main container.
423  ignoredItemCount = Inventory.AllItems.Count(it => subContainableItems.Any(ri => !ri.MatchesItem(it)));
424  capacity = targetSlotCapacity * (Capacity - MainContainerCapacity);
425  }
426  }
427  int itemCount = Inventory.AllItems.Count() - ignoredItemCount;
428  return Math.Min(itemCount / Math.Max(capacity, 1), 1);
429  }
430 
431  //display the state of an item in a specific slot
433  {
434  if (containedItem == null) { return 0.0f; }
435  //if the contained item has some contained state indicator, show that
436  if (containedItem.GetComponent<ItemContainer>() is { ShowContainedStateIndicator: true } containedItemContainer)
437  {
438  return containedItemContainer.GetContainedIndicatorState();
439  }
440  int maxStackSize = Math.Min(containedItem.Prefab.GetMaxStackSize(Inventory), GetMaxStackSize(targetSlot));
441  if (maxStackSize == 1)
442  {
443  return containedItem.Condition / containedItem.MaxCondition;
444  }
445  return containedItems.Count() / (float)maxStackSize;
446  }
447  else
448  {
449  return Inventory.EmptySlotCount / (float)Inventory.Capacity;
450  }
451  }
452 
453  public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1, Color? overrideColor = null)
454  {
455  if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
456  DrawContainedItems(spriteBatch, itemDepth, overrideColor);
457  }
458 
459  public void DrawContainedItems(SpriteBatch spriteBatch, float itemDepth, Color? overrideColor = null)
460  {
461  Vector2 transformedItemPos = ItemPos * item.Scale;
462  Vector2 transformedItemInterval = ItemInterval * item.Scale;
463  Vector2 transformedItemIntervalHorizontal = new Vector2(transformedItemInterval.X, 0.0f);
464  Vector2 transformedItemIntervalVertical = new Vector2(0.0f, transformedItemInterval.Y);
465 
466  if (item.body == null)
467  {
468  if (item.FlippedX)
469  {
470  transformedItemPos.X = -transformedItemPos.X;
471  transformedItemPos.X += item.Rect.Width;
472  transformedItemInterval.X = -transformedItemInterval.X;
473  transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
474  }
475  if (item.FlippedY)
476  {
477  transformedItemPos.Y = -transformedItemPos.Y;
478  transformedItemPos.Y -= item.Rect.Height;
479  transformedItemInterval.Y = -transformedItemInterval.Y;
480  transformedItemIntervalVertical.Y = -transformedItemIntervalVertical.Y;
481  }
482  transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
483  if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; }
484 
485  if (Math.Abs(item.RotationRad) > 0.01f)
486  {
487  Matrix transform = Matrix.CreateRotationZ(-item.RotationRad);
488  transformedItemPos = Vector2.Transform(transformedItemPos - item.DrawPosition, transform) + item.DrawPosition;
489  transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
490  transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
491  transformedItemIntervalVertical = Vector2.Transform(transformedItemIntervalVertical, transform);
492  }
493  }
494  else
495  {
496  Matrix transform = Matrix.CreateRotationZ(item.body.DrawRotation);
497  if (item.body.Dir == -1.0f)
498  {
499  transformedItemPos.X = -transformedItemPos.X;
500  transformedItemInterval.X = -transformedItemInterval.X;
501  transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
502  }
503 
504  transformedItemPos = Vector2.Transform(transformedItemPos, transform);
505  transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
506  transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
507  transformedItemPos += item.body.DrawPosition;
508  }
509 
510  Vector2 currentItemPos = transformedItemPos;
511 
513 
514  int i = 0;
515  foreach (ContainedItem contained in containedItems)
516  {
517  Vector2 itemPos = currentItemPos;
518 
519  if (contained.Item?.Sprite == null) { continue; }
520 
521  if (contained.Hide) { continue; }
522  if (contained.ItemPos.HasValue)
523  {
524  Vector2 pos = contained.ItemPos.Value;
525  if (item.body != null)
526  {
527  Matrix transform = Matrix.CreateRotationZ(item.body.DrawRotation);
528  pos.X *= item.body.Dir;
529  itemPos = Vector2.Transform(pos, transform) + item.body.DrawPosition;
530  }
531  else
532  {
533  itemPos = pos;
534  // This code is aped based on above. Not tested.
535  if (item.FlippedX)
536  {
537  itemPos.X = -itemPos.X;
538  itemPos.X += item.Rect.Width;
539  }
540  if (item.FlippedY)
541  {
542  itemPos.Y = -itemPos.Y;
543  itemPos.Y -= item.Rect.Height;
544  }
545  itemPos += new Vector2(item.Rect.X, item.Rect.Y);
546  if (item.Submarine != null)
547  {
548  itemPos += item.Submarine.DrawPosition;
549  }
550  if (Math.Abs(item.RotationRad) > 0.01f)
551  {
552  Matrix transform = Matrix.CreateRotationZ(-item.RotationRad);
553  itemPos = Vector2.Transform(itemPos - item.DrawPosition, transform) + item.DrawPosition;
554  }
555  }
556  }
557 
559  {
560  contained.Item.IsHighlighted = item.IsHighlighted;
561  item.IsHighlighted = false;
562  }
563 
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; }
567 
568  float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? contained.Item.Sprite.Depth : ContainedSpriteDepth;
569  if (i < containedSpriteDepths.Length)
570  {
571  containedSpriteDepth = containedSpriteDepths[i];
572  }
573  containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f;
574 
575  SpriteEffects spriteEffects = SpriteEffects.None;
576  float spriteRotation = ItemRotation;
577  if (contained.Rotation != 0)
578  {
579  spriteRotation = contained.Rotation;
580  }
581  bool flipX = (item.body != null && item.body.Dir == -1) || item.FlippedX;
582  if (flipX)
583  {
584  spriteEffects |= MathUtils.NearlyEqual(spriteRotation % 180, 90.0f) ? SpriteEffects.FlipVertically : SpriteEffects.FlipHorizontally;
585  }
586  bool flipY = item.FlippedY;
587  if (flipY)
588  {
589  spriteEffects |= MathUtils.NearlyEqual(spriteRotation % 180, 90.0f) ? SpriteEffects.FlipHorizontally : SpriteEffects.FlipVertically;
590  }
591 
592  contained.Item.Sprite.Draw(
593  spriteBatch,
594  new Vector2(itemPos.X, -itemPos.Y),
595  overrideColor ?? (isWiringMode ? contained.Item.GetSpriteColor(withHighlight: true) * 0.15f : contained.Item.GetSpriteColor(withHighlight: true)),
596  origin,
597  -(contained.Item.body == null ? 0.0f : contained.Item.body.DrawRotation),
598  contained.Item.Scale,
599  spriteEffects,
600  depth: containedSpriteDepth);
601  contained.Item.DrawDecorativeSprites(spriteBatch, itemPos, flipX,flipY, (contained.Item.body == null ? 0.0f : contained.Item.body.DrawRotation),
602  containedSpriteDepth, overrideColor);
603 
604  foreach (ItemContainer ic in contained.Item.GetComponents<ItemContainer>())
605  {
606  if (ic.hideItems) { continue; }
607  ic.DrawContainedItems(spriteBatch, containedSpriteDepth, overrideColor);
608  }
609 
610  i++;
611  if (Math.Abs(ItemInterval.X) > 0.001f && Math.Abs(ItemInterval.Y) > 0.001f)
612  {
613  //interval set on both axes -> use a grid layout
614  currentItemPos += transformedItemIntervalHorizontal;
615  if (i % ItemsPerRow == 0)
616  {
617  currentItemPos = transformedItemPos;
618  currentItemPos += transformedItemIntervalVertical * (i / ItemsPerRow);
619  }
620  }
621  else
622  {
623  currentItemPos += transformedItemInterval;
624  }
625  }
626  }
627 
628  public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
629  {
630  if (!item.IsInteractable(character)) { return; }
631  if (Inventory.RectTransform != null)
632  {
633  guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;
634  }
635 
636  if (item.ParentInventory?.Owner == character && character.SelectedItem == item)
637  {
638  character.SelectedItem = null;
639  }
640 
641  //if the item is in the character's inventory, no need to update the item's inventory
642  //because the player can see it by hovering the cursor over the item
643  guiCustomComponent.Visible = DrawInventory && (item.ParentInventory?.Owner != character || Inventory.DrawWhenEquipped);
644  if (!guiCustomComponent.Visible) { return; }
645 
646  Inventory.Update(deltaTime, cam);
647  }
648  }
649 }
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
Definition: Entity.cs:51
Submarine Submarine
Definition: Entity.cs:53
virtual Rectangle Rect
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)
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.
void OnGUIParentChanged(RectTransform newParent)
Launches when the parent of the GuiFrame is changed.
float ContainedSpriteDepth
Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is...
override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
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....
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
ContentPackage? ContentPackage
Definition: Prefab.cs:37
Vector2 RelativeSize
Relative to the parent rect.
void Resize(Point absoluteSize, bool resizeChildren=true)
RectTransform(Vector2 relativeSize, RectTransform parent, Anchor anchor=Anchor.TopLeft, Pivot? pivot=null, Point? minSize=null, Point? maxSize=null, ScaleBasis scaleBasis=ScaleBasis.Normal)
Action< RectTransform > ParentChanged
Point?? MaxSize
Max size in pixels. Does not affect scaling.
static bool IsWiringMode()