4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Graphics;
7 using System.Collections.Generic;
49 private static Rectangle offScreenRect =
new Rectangle(
new Point(-1000, 0), Point.Zero);
56 if (
IsMoving) {
return offScreenRect; }
65 return new Rectangle((
int)equipIndicatorPos.X, (
int)equipIndicatorPos.Y, (
int)
Rect.Width, (
int)sizeY);
75 Color = Color.White * 0.4f;
85 public void ShowBorderHighlight(Color color,
float fadeInDuration,
float fadeOutDuration,
float scaleUpAmount = 0.5f)
87 if (highlightCoroutine !=
null)
89 CoroutineManager.StopCoroutines(highlightCoroutine);
90 highlightCoroutine =
null;
94 currentHighlightState = 0.0f;
95 this.fadeInDuration = fadeInDuration;
96 this.fadeOutDuration = fadeOutDuration;
97 currentHighlightColor = color;
99 highlightCoroutine = CoroutineManager.StartCoroutine(UpdateBorderHighlight());
102 private float currentHighlightState, fadeInDuration, fadeOutDuration;
103 private Color currentHighlightColor;
104 private IEnumerable<CoroutineStatus> UpdateBorderHighlight()
107 while (currentHighlightState < fadeInDuration + fadeOutDuration)
110 Color.Lerp(Color.Transparent, currentHighlightColor, currentHighlightState / fadeInDuration) :
111 Color.Lerp(currentHighlightColor, Color.Transparent, (currentHighlightState - fadeInDuration) / fadeOutDuration);
113 currentHighlightState += CoroutineManager.DeltaTime;
114 HighlightTimer = 1.0f - currentHighlightState / (fadeInDuration + fadeOutDuration);
122 yield
return CoroutineStatus.Success;
130 if (highlightCoroutine ==
null) {
return; }
131 CoroutineManager.StopCoroutines(highlightCoroutine);
132 highlightCoroutine =
null;
135 newSlot.currentHighlightState = currentHighlightState;
136 newSlot.fadeInDuration = fadeInDuration;
137 newSlot.fadeOutDuration = fadeOutDuration;
138 newSlot.currentHighlightColor = currentHighlightColor;
139 newSlot.highlightCoroutine = CoroutineManager.StartCoroutine(newSlot.UpdateBorderHighlight());
143 partial class Inventory
152 get {
return (
int)(15 *
UIScale); }
161 private static Sprite slotSpriteSmall;
166 if (slotSpriteSmall ==
null)
169 slotSpriteSmall =
new Sprite(
"Content/UI/InventoryUIAtlas.png",
new Rectangle(10, 6, 119, 120),
null, 0);
173 return slotSpriteSmall;
180 public static Sprite UnequippedIndicator, UnequippedHoverIndicator, UnequippedClickedIndicator, EquippedIndicator, EquippedHoverIndicator, EquippedClickedIndicator;
188 private List<ushort>[] partialReceivedItemIDs;
189 private List<ushort>[] receivedItemIDs;
194 private bool isSubInventory;
196 private const float movableFrameRectHeight = 40f;
197 private Color movableFrameRectColor =
new Color(60, 60, 60);
199 private Point savedPosition, originalPos;
200 private bool canMove =
false;
201 private bool positionUpdateQueued =
false;
202 private Vector2 draggableIndicatorOffset;
203 private float draggableIndicatorScale;
236 if (
Item ==
null) {
return false; }
244 if (
Item ==
null) {
return; }
245 IEnumerable<Item> itemsInSlot =
null;
257 if (item ==
null) {
return null; }
267 if (item.
HasTag(Tags.IdCardTag) || item.
HasTag(Tags.DespawnContainer))
269 string[] readTags = item.
Tags.Split(
',');
270 string idName =
null;
272 foreach (
string tag
in readTags)
274 string[] s = tag.Split(
':');
290 description = TextManager.GetWithVariable(
"IDCardName",
"[name]", idName);
294 description = TextManager.GetWithVariables(
"IDCardNameJob",
296 (
"[job]", TextManager.Get(
"jobname." + idJob).Fallback(idJob),
FormatCapitals.Yes));
300 description = description +
" " + item.
Description;
305 LocalizedString name = item.
Name;
316 description += itemCount == 1 ?
318 "\n " + itemName +
" x" + itemCount;
322 string colorStr = (item.
Illegitimate ? GUIStyle.Red : Color.White).ToStringHex();
324 toolTip = $
"‖color:{colorStr}‖{name}‖color:end‖";
325 if (item.GetComponent<
Quality>() !=
null)
327 toolTip +=
"\n" + TextManager.GetWithVariable(
"itemname.quality" + item.
Quality,
"[itemname]",
"")
328 .
Fallback(TextManager.GetWithVariable(
"itemname.quality3",
"[itemname]",
""))
332 if (itemsInSlot.All(it => !it.IsInteractable(
Character.Controlled)))
334 toolTip +=
" " + TextManager.Get(
"connectionlocked");
338 string conditionColorStr = XMLExtensions.ToStringHex(ToolBox.GradientLerp(item.
Condition / item.
MaxCondition, GUIStyle.ColorInventoryEmpty, GUIStyle.ColorInventoryHalf, GUIStyle.ColorInventoryFull));
339 toolTip += $
"‖color:{conditionColorStr}‖ ({(int)item.ConditionPercentage} %)‖color:end‖";
341 if (!description.IsNullOrEmpty()) { toolTip +=
'\n' + description; }
344 colorStr = XMLExtensions.ToStringHex(Color.MediumPurple);
345 toolTip += $
"\n‖color:{colorStr}‖{item.Prefab.ContentPackage.Name}‖color:end‖";
348 if (itemsInSlot.Count() > 1)
350 toolTip += $
"\n‖color:gui.blue‖[{GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.TakeOneFromInventorySlot)}] {TextManager.Get("inputtype.takeonefrominventoryslot
")}‖color:end‖";
351 toolTip += $
"\n‖color:gui.blue‖[{GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.TakeHalfFromInventorySlot)}] {TextManager.Get("inputtype.takehalffrominventoryslot
")}‖color:end‖";
358 toolTip += $
" ({item.Prefab.Identifier})";
360 if (PlayerInput.KeyDown(
InputType.ContextualCommand))
362 toolTip += $
"\n‖color:gui.blue‖{TextManager.ParseInputTypes(TextManager.Get("itemmsgcontextualorders
"))}‖color:end‖";
366 var colorStr = XMLExtensions.ToStringHex(Color.LightGray * 0.7f);
367 toolTip += $
"\n‖color:{colorStr}‖{TextManager.Get("itemmsg.morreoptionsavailable
")}‖color:end‖";
370 return RichString.Rich(toolTip);
391 private int slotsPerRow;
394 set { slotsPerRow = Math.Max(1, value); }
398 private static readonly List<SlotReference> subInventorySlotsToDraw =
new List<SlotReference>();
437 int rows = (int)Math.Ceiling((
double)
capacity / slotsPerRow);
438 int columns = Math.Min(slotsPerRow,
capacity);
440 Vector2 spacing =
new Vector2(5.0f *
UIScale);
442 Vector2 rectSize =
new Vector2(60.0f *
UIScale);
444 padding =
new Vector4(spacing.X, spacing.Y, spacing.X, spacing.X);
447 Vector2 slotAreaSize =
new Vector2(
448 columns * rectSize.X + (columns - 1) * spacing.X,
449 rows * rectSize.Y + (rows - 1) * spacing.Y);
453 Vector2 topLeft =
new Vector2(
457 Vector2 center = topLeft + slotAreaSize / 2;
461 Vector2 scale =
new Vector2(
476 Rectangle slotRect =
new Rectangle((
int)topLeft.X, (
int)topLeft.Y, (
int)rectSize.X, (
int)rectSize.Y);
479 int row = (int)Math.Floor((
double)i / slotsPerRow);
480 int slotsPerThisRow = Math.Min(slotsPerRow,
capacity - row * slotsPerRow);
481 int slotNumberOnThisRow = i - row * slotsPerRow;
483 int rowWidth = (int)(rectSize.X * slotsPerThisRow + spacing.X * (slotsPerThisRow - 1));
484 slotRect.X = (int)(center.X) - rowWidth / 2;
485 slotRect.X += (int)((rectSize.X + spacing.X) * (slotNumberOnThisRow % slotsPerThisRow));
487 slotRect.Y = (int)(topLeft.Y + (rectSize.Y + spacing.Y) * row);
516 return movableFrameRect.Size != Point.Zero;
526 if (container ==
null) {
return false; }
535 public virtual void Update(
float deltaTime,
Camera cam,
bool subInventory =
false)
537 if (
visualSlots ==
null || isSubInventory != subInventory ||
541 isSubInventory = subInventory;
570 interactRect.Location += slot.
DrawOffset.ToPoint();
572 bool mouseOnGUI =
false;
640 if (CanSelectSlot(slotRef))
649 if (interactableItems.Any())
651 if (availableContextualOrder.target !=
null)
658 availableContextualOrder =
default;
670 DraggingItems.AddRange(interactableItems.Skip(interactableItems.Count() / 2));
712 if (container ==
null) {
return null; }
727 if (item ==
null) {
return; }
730 if (container ==
null || !container.DrawInventory) {
return; }
731 if (container.Inventory.DrawWhenEquipped) {
return; }
734 if (subInventory.visualSlots ==
null) { subInventory.
CreateSlots(); }
736 canMove = container.MovableFrame && !subInventory.IsInventoryHoverAvailable(
Owner as
Character, container) && subInventory.originalPos != Point.Zero;
744 subInventory.HideTimer = 1.0f;
745 subInventory.OpenState = 1.0f;
748 container.Inventory.savedPosition = container.Inventory.originalPos;
774 int itemCapacity = subInventory.slots.Length;
782 int columns = MathHelper.Clamp((
int)Math.Floor(Math.Sqrt(itemCapacity)), 1, container.SlotsPerRow);
788 int width = (int)(subRect.Width * columns + spacing.X * (columns - 1));
789 int startX = slot.Rect.Center.X - (int)(width / 2.0f);
790 int startY = dir < 0 ?
791 slot.EquipButtonRect.Y - subRect.Height - (int)(35 *
UIScale) :
792 slot.EquipButtonRect.Bottom + (int)(10 *
UIScale);
796 startX += subInventory.savedPosition.X - subInventory.originalPos.X;
797 startY += subInventory.savedPosition.Y - subInventory.originalPos.Y;
800 float totalHeight = itemCapacity / columns * (subRect.Height + spacing.Y);
804 startX = Math.Max(startX,
padding);
809 startY = Math.Max(startY, (
int)totalHeight -
padding / 2);
816 subInventory.OpenState = subInventory.HideTimer >= 0.5f ?
817 Math.Min(subInventory.OpenState + deltaTime * 8.0f, 1.0f) :
818 Math.Max(subInventory.OpenState - deltaTime * 5.0f, 0.0f);
820 for (
int i = 0; i < itemCapacity; i++)
822 subInventory.visualSlots[i].Rect = subRect;
823 subInventory.visualSlots[i].Rect.Location +=
new Point(0, (
int)totalHeight * -dir);
825 subInventory.visualSlots[i].DrawOffset = Vector2.SmoothStep(
new Vector2(0, -50 * dir),
new Vector2(0, totalHeight * dir), subInventory.OpenState);
827 subInventory.visualSlots[i].InteractRect =
new Rectangle(
828 (
int)(subInventory.visualSlots[i].Rect.X - spacing.X / 2 - 1), (
int)(subInventory.visualSlots[i].Rect.Y - spacing.Y / 2 - 1),
829 (
int)(subInventory.visualSlots[i].Rect.Width + spacing.X + 2), (
int)(subInventory.visualSlots[i].Rect.Height + spacing.Y + 2));
831 if ((i + 1) % columns == 0)
834 subRect.Y += subRect.Height * dir;
835 subRect.Y += (int)(spacing.Y * dir);
839 subRect.X = (int)(subInventory.visualSlots[i].Rect.Right + spacing.X);
845 subInventory.movableFrameRect.X = subRect.X - (int)spacing.X;
846 subInventory.movableFrameRect.Y = subRect.Y + (
int)(spacing.Y);
850 subInventory.isSubInventory =
true;
851 subInventory.Update(deltaTime, cam,
true);
866 public virtual void Draw(SpriteBatch spriteBatch,
bool subInventory =
false)
868 if (
visualSlots ==
null || isSubInventory != subInventory) {
return; }
909 private static bool DetermineMouseOnInventory(
bool ignoreDraggedItem =
false)
916 if (GameSession.IsTabMenuOpen) {
return false; }
917 if (CrewManager.IsCommandInterfaceOpen) {
return false; }
919 if (
Character.Controlled ==
null) {
return false; }
921 if (!ignoreDraggedItem)
926 var isSubEditor = Screen.Selected is SubEditorScreen editor && !editor.WiringMode;
928 if (
Character.Controlled.Inventory !=
null && !isSubEditor)
930 if (IsOnInventorySlot(
Character.Controlled.Inventory)) {
return true; }
933 if (
Character.Controlled.SelectedCharacter?.Inventory !=
null && !isSubEditor)
935 if (IsOnInventorySlot(
Character.Controlled.SelectedCharacter.Inventory)) {
return true; }
938 static bool IsOnInventorySlot(
Inventory inventory)
940 for (var i = 0; i < inventory.visualSlots.Length; i++)
942 if (inventory.HideSlot(i)) {
continue; }
943 var slot = inventory.visualSlots[i];
944 if (slot.InteractRect.Contains(PlayerInput.MousePosition))
950 if (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) &&
951 i >= 0 && inventory.slots.Length > i &&
952 !inventory.slots[i].Empty())
960 if (
Character.Controlled.SelectedItem !=
null)
962 foreach (var ic
in Character.Controlled.SelectedItem.ActiveHUDs)
967 foreach (VisualSlot slot
in itemContainer.Inventory.visualSlots)
969 if (slot.InteractRect.Contains(PlayerInput.MousePosition) ||
970 slot.EquipButtonRect.Contains(PlayerInput.MousePosition))
989 if (character ==
null) {
return CursorState.Default; }
993 var selInv = character.SelectedCharacter?.
Inventory;
997 foreach (var item
in inv.AllItems)
1000 if (container ==
null) {
continue; }
1002 if (container.Inventory.visualSlots !=
null)
1004 if (container.Inventory.visualSlots.Any(slot => slot.IsHighlighted))
1018 for (
int i = 0; i < selInv.visualSlots.Length; i++)
1021 Item item = selInv.slots[i].FirstOrDefault();
1028 if (container ==
null) {
continue; }
1029 if (container.Inventory.visualSlots !=
null)
1031 if (container.Inventory.visualSlots.Any(slot => slot.
IsHighlighted))
1045 if (!ic.Item.IsInteractable(character)) {
continue; }
1047 foreach (var slot
in itemContainer.Inventory.visualSlots)
1058 for (
int i = 0; i < inv.visualSlots.Length; i++)
1061 Item item = inv.slots[i].FirstOrDefault();
1089 if (item ==
null) {
return; }
1092 if (container ==
null || !container.DrawInventory) {
return; }
1094 if (container.Inventory.visualSlots ==
null || !container.Inventory.isSubInventory) {
return; }
1095 if (container.Inventory.DrawWhenEquipped) {
return; }
1097 int itemCapacity = container.
Capacity;
1100 System.Diagnostics.Debug.Assert(slotIndex >= 0 && slotIndex <
slots.Length);
1102 if (slotIndex < 0 || slotIndex >=
capacity) {
return; }
1107 Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
1112 spriteBatch.GraphicsDevice.ScissorRectangle =
new Rectangle(
1118 spriteBatch.GraphicsDevice.ScissorRectangle =
new Rectangle(
1122 container.Inventory.Draw(spriteBatch,
true);
1124 spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
1125 spriteBatch.Begin(SpriteSortMode.Deferred);
1129 container.Inventory.Draw(spriteBatch,
true);
1132 container.InventoryBottomSprite?.Draw(spriteBatch,
1136 container.InventoryTopSprite?.Draw(spriteBatch,
1139 container.Inventory.visualSlots[container.Inventory.visualSlots.Length - 1].
Rect.Y) + container.Inventory.visualSlots[container.Inventory.visualSlots.Length - 1].DrawOffset,
1144 if (container.Inventory.positionUpdateQueued)
1146 int height = (int)(movableFrameRectHeight *
UIScale);
1148 container.Inventory.movableFrameRect =
new Rectangle(container.Inventory.BackgroundFrame.X, container.Inventory.BackgroundFrame.Y - height, container.Inventory.BackgroundFrame.Width, height);
1149 draggableIndicatorScale = 1.25f *
UIScale;
1151 draggableIndicatorOffset +=
new Vector2(height / 2f - draggableIndicatorOffset.Y);
1152 container.Inventory.originalPos = container.Inventory.savedPosition = container.Inventory.movableFrameRect.Center;
1153 container.Inventory.positionUpdateQueued =
false;
1159 container.Inventory.savedPosition = container.Inventory.originalPos;
1164 container.Inventory.positionUpdateQueued =
true;
1168 Color color = movableFrameRectColor;
1177 GUI.DrawRectangle(spriteBatch, container.Inventory.movableFrameRect, color,
true);
1178 DraggableIndicator.
Draw(spriteBatch, container.Inventory.movableFrameRect.Location.ToVector2() + draggableIndicatorOffset, 0, draggableIndicatorScale);
1195 if (!DetermineMouseOnInventory(ignoreDraggedItem:
true) &&
1198 if (TryPortraitAndHealthDrop(mouseOnPortrait))
1206 HandleOutsideInventoryDrop();
1210 HandleInventorySlotDrop();
1221 bool TryPortraitAndHealthDrop(
bool mouseOnPortrait)
1223 bool dropSuccessful =
false;
1231 if (indices !=
null && inventory.visualSlots !=
null)
1233 foreach (
int i
in indices)
1235 inventory.visualSlots[i]?.ShowBorderHighlight(GUIStyle.Green, 0.1f, 0.4f);
1250 void HandleOutsideInventoryDrop()
1255 container.AllowDragAndDrop &&
1262 bool anySuccess =
false;
1265 bool success =
false;
1266 if (isTargetingValidContainer)
1270 if (!success && isTargetingValidCharacter)
1275 if (!success) {
break; }
1279 if (anySuccess) { SoundPlayer.PlayUISound(
GUISoundType.PickItem); }
1292 bool removed =
false;
1302 if (editor.WiringMode)
1322 void HandleInventorySlotDrop()
1327 int oldSlot = oldInventory ==
null ? 0 : Array.IndexOf(oldInventory.slots,
DraggingItems);
1330 if (selectedInventory.slots[slotIndex].Empty() &&
1335 if (selectedInventory.visualSlots !=
null)
1337 for (
int i = 0; i < selectedInventory.visualSlots.Length; i++)
1339 if (
DraggingItems.Any(it => selectedInventory.slots[i].Contains(it)))
1341 selectedInventory.visualSlots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
1344 selectedInventory.visualSlots[slotIndex].ShowBorderHighlight(GUIStyle.Red, 0.1f, 0.9f);
1350 bool anySuccess =
false;
1354 bool allowCombine = !(
DraggingItems.Count(it => !it.IsFullCondition && it.Condition > 0.0f) > 1 ||
1355 selectedInventory.GetItemsAt(slotIndex).Count(it => !it.IsFullCondition && it.Condition > 0.0f) > 1);
1359 if (selectedInventory.GetItemAt(slotIndex)?.OwnInventory?.Container is { } container &&
1360 container.Inventory.CanBePut(item))
1362 if (!container.AllowDragAndDrop || !container.AllowAccess)
1364 allowCombine =
false;
1367 bool success = selectedInventory.TryPutItem(item, slotIndex, allowSwapping: !anySuccess, allowCombine,
Character.
Controlled);
1386 if (selectedInventory.slots[slotIndex].Contains(draggingItem))
1392 if (selectedInventory.visualSlots !=
null) { selectedInventory.visualSlots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f); }
1397 if (selectedInventory.visualSlots !=
null){ selectedInventory.visualSlots[slotIndex].ShowBorderHighlight(GUIStyle.Red, 0.1f, 0.9f); }
1402 selectedInventory.HideTimer = 2.0f;
1405 for (
int i = 0; i < parentItem.ParentInventory.capacity; i++)
1407 if (parentItem.ParentInventory.HideSlot(i)) {
continue; }
1408 if (parentItem.ParentInventory.slots[i].FirstOrDefault() != parentItem) {
continue; }
1411 parentItem.ParentInventory, parentItem.ParentInventory.visualSlots[i],
1421 private static bool IsValidTargetForDragDropGive(
Character giver,
Character receiver)
1423 if (giver ==
null || receiver ==
null) {
return false; }
1424 if (receiver == giver) {
return false; }
1428 private static bool CanSelectSlot(SlotReference
selectedSlot)
1440 static bool OwnerInaccessible(Entity owner) =>
1442 owner !=
Character.Controlled.SelectedCharacter &&
1443 owner !=
Character.Controlled.SelectedItem &&
1444 (
Character.Controlled.SelectedItem ==
null || !
Character.Controlled.SelectedItem.linkedTo.Contains(owner));
1447 Entity rootOwner = (owner as
Item)?.GetRootInventoryOwner();
1448 if (OwnerInaccessible(owner) && (rootOwner == owner || OwnerInaccessible(rootOwner)))
1453 if (parentItem?.GetRootInventoryOwner() is
Character ownerCharacter)
1455 if (ownerCharacter ==
Character.Controlled &&
1456 CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
1457 ownerCharacter.Inventory.IsInLimbSlot(parentItem,
InvSlotType.HealthInterface) &&
1458 Screen.Selected != GameMain.SubEditorScreen)
1481 if (subEditorCharacterInventoryHidden || (isMovable && !unEquipped && isDefaultLayout))
1503 subSlotRect.Location += slot.
DrawOffset.ToPoint();
1504 hoverArea =
Rectangle.Union(hoverArea, subSlotRect);
1514 int over = subSlot.
Slot.
Rect.Y - hoverArea.Y;
1515 hoverArea.Y += over;
1516 hoverArea.Height -= over;
1520 float inflateAmount = 10 *
UIScale;
1522 hoverArea.Inflate(inflateAmount, inflateAmount);
1528 if (GUI.PauseMenuOpen || GUI.SettingsMenuOpen) {
return; }
1532 subInventorySlotsToDraw.Clear();
1534 foreach (var slot
in subInventorySlotsToDraw)
1536 int slotIndex = Array.IndexOf(slot.ParentInventory.visualSlots, slot.Slot);
1537 if (slotIndex > -1 && slotIndex < slot.ParentInventory.visualSlots.Length &&
1540 slot.ParentInventory.DrawSubInventory(spriteBatch, slotIndex);
1558 if (!slotIconTooltip.IsNullOrEmpty())
1560 DrawToolTip(spriteBatch, slotIconTooltip, slotRect);
1566 slotIconTooltip =
string.Empty;
1569 void DrawDragRelated()
1575 int iconSize = (int)(64 * GUI.Scale);
1576 float scale = Math.Min(Math.Min(iconSize / sprite.
size.X, iconSize / sprite.
size.Y), 1.5f);
1579 bool mouseOnHealthInterface =
1582 mouseOnHealthInterface = mouseOnHealthInterface &&
DraggingItems.Any(it => it.UseInHealthInterface);
1584 if ((GUI.MouseOn ==
null || mouseOnHealthInterface) &&
selectedSlot ==
null)
1588 (
LocalizedString toolTip, Color toolTipColor) = GetDragLabelTextAndColor(mouseOnHealthInterface);
1590 Vector2 nameSize = GUIStyle.Font.MeasureString(
DraggingItems.First().Name);
1591 Vector2 toolTipSize = GUIStyle.SmallFont.MeasureString(toolTip);
1592 int textWidth = (int)Math.Max(nameSize.X, toolTipSize.X);
1593 int textSpacing = (int)(15 * GUI.Scale);
1595 Vector2 textPos = itemPos;
1597 int textOffset = textDir == 1 ? 0 : -1;
1598 textPos +=
new Vector2((iconSize / 2 + textSpacing) * textDir, 0);
1600 Point shadowPadding =
new Point(40, 20).Multiply(GUI.Scale);
1601 Point shadowSize =
new Point(iconSize + textWidth + textSpacing, iconSize) + shadowPadding.Multiply(2);
1603 shadowSprite.Draw(spriteBatch,
1604 new Rectangle(itemPos.ToPoint() -
new Point((iconSize / 2 - shadowPadding.X) * textDir - shadowSize.X * textOffset, iconSize / 2 + shadowPadding.Y), shadowSize), Color.Black * 0.8f);
1606 GUI.DrawString(spriteBatch, textPos +
new Vector2(nameSize.X * textOffset, -iconSize / 2),
DraggingItems.First().Name, Color.White);
1607 GUI.DrawString(spriteBatch, textPos +
new Vector2(toolTipSize.X * textOffset, 0), toolTip,
1608 color: toolTipColor,
1609 font: GUIStyle.SmallFont);
1614 sprite.
Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black, scale: scale);
1615 sprite.
Draw(spriteBatch,
1627 int maxAmountPerSlot = 0;
1630 maxAmountPerSlot = Math.Max(
1634 stackAmount = Math.Min(stackAmount, maxAmountPerSlot);
1638 stackAmount = Math.Min(
1643 Vector2 stackCountPos = itemPos + Vector2.One * iconSize * 0.25f;
1644 string stackCountText =
"x" + stackAmount;
1645 GUIStyle.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos + Vector2.One, Color.Black);
1646 GUIStyle.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, GUIStyle.TextColorBright);
1651 (
LocalizedString, Color) GetDragLabelTextAndColor(
bool mouseOnHealthInterface)
1655 Color toolTipColor = Color.LightGreen;
1658 if (mouseOnHealthInterface)
1660 toolTip = TextManager.Get(
"QuickUseAction.UseTreatment");
1666 else if (useDragDropGive)
1672 toolTipColor = GUIStyle.Red;
1675 return (toolTip, toolTipColor);
1679 private static (
Item target, Identifier orderIdentifier) availableContextualOrder;
1690 rect.Inflate(rect.Width * inflateAmount, rect.Height * inflateAmount);
1693 Color slotColor = Color.White;
1694 Item parentItem = inventory?.Owner as
Item;
1697 if (itemContainer !=
null && (itemContainer.InventoryTopSprite !=
null || itemContainer.InventoryBottomSprite !=
null))
1702 itemContainer.InventoryTopSprite?.Draw(spriteBatch,
new Vector2(rect.Center.X, rect.Y), 0,
UIScale);
1711 if (inventory !=
null && inventory.Locked) { slotColor = Color.Gray * 0.5f; }
1716 GUI.DrawRectangle(spriteBatch, rect, GUIStyle.Red * 0.3f, isFilled:
true);
1719 bool canBePut =
false;
1721 if (
DraggingItems.Any() && inventory !=
null && slotIndex > -1 && slotIndex < inventory.visualSlots.Length)
1723 var itemInSlot = inventory.slots[slotIndex].FirstOrDefault();
1724 if (inventory.CanBePutInSlot(
DraggingItems.First(), slotIndex))
1729 (itemInSlot?.OwnInventory !=
null &&
1731 itemInSlot.OwnInventory.Container.AllowDragAndDrop &&
1732 itemInSlot.OwnInventory.Container.DrawInventory)
1745 GUIStyle.UIGlow.Draw(spriteBatch, rect, GUIStyle.Green);
1748 if (item !=
null && drawItem)
1754 if (itemContainer !=
null && itemContainer.ShowContainedStateIndicator)
1756 conditionIndicatorArea =
new Rectangle(rect.X, rect.Bottom - (
int)(10 * GUI.Scale), rect.Width, (
int)(10 * GUI.Scale));
1761 rect.X, dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 -
ContainedIndicatorHeight,
1763 conditionIndicatorArea.Inflate(-4, 0);
1766 var indicatorStyle = GUIStyle.GetComponentStyle(
"ContainedStateIndicator.Default");
1767 Sprite indicatorSprite = indicatorStyle?.GetDefaultSprite();
1769 DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.
Condition / item.
MaxCondition);
1772 if (itemContainer !=
null && itemContainer.ShowContainedStateIndicator && itemContainer.Capacity > 0)
1774 float containedState = itemContainer.GetContainedIndicatorState();
1778 containedIndicatorArea.Inflate(-4, 0);
1781 itemContainer.ContainedStateIndicator ??
1782 itemContainer.IndicatorStyle?.GetDefaultSprite();
1783 Sprite emptyIndicatorSprite =
1784 itemContainer.ContainedStateIndicatorEmpty ??
1787 bool usingDefaultSprite = itemContainer.IndicatorStyle?.
Name ==
"ContainedStateIndicator.Default";
1789 DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, containedIndicatorArea, containedState,
1795 var style = GUIStyle.GetComponentStyle(
"InnerGlowSmall");
1798 GUI.DrawRectangle(spriteBatch, rect, GUIStyle.GetQualityColor(item.
Quality) * 0.7f);
1808 var slotIcon = parentItem?.GetComponent<
ItemContainer>()?.GetSlotIcon(slotIndex);
1809 if (slotIcon !=
null)
1811 slotIcon.Draw(spriteBatch, rect.Center.ToVector2(), GUIStyle.EquipmentSlotIconColor, scale: Math.Min(rect.Width / slotIcon.size.X, rect.Height / slotIcon.size.Y) * 0.8f);
1818 GUI.DrawRectangle(spriteBatch, rect, Color.White,
false, 0, 1);
1819 GUI.DrawRectangle(spriteBatch, slot.
EquipButtonRect, Color.White,
false, 0, 1);
1827 if (item !=
null && drawItem)
1830 float scale = Math.Min(Math.Min((rect.Width - 10) / sprite.
size.X, (rect.Height - 10) / sprite.
size.Y), 2.0f);
1831 Vector2 itemPos = rect.Center.ToVector2();
1834 itemPos.Y -= Math.Min(
1836 (itemPos.Y - sprite.
size.Y / 2 * scale) - rect.Y);
1839 float rotation = 0.0f;
1846 if (inventory !=
null && (inventory.Locked || inventory.slots[slotIndex].Items.All(it => !it.IsInteractable(
Character.
Controlled)))) { spriteColor *= 0.5f; }
1849 spriteColor = Color.Lerp(spriteColor, Color.TransparentBlack, 0.5f);
1853 sprite.
Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black * 0.6f, rotate: rotation, scale: scale);
1855 sprite.
Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
1861 DrawSideIcon(ignoreOrder.SymbolSprite,
Direction.Right, TextManager.Get(
"tooltip.ignored"), ignoreOrder.Color, out
bool mouseOn);
1862 if (mouseOn) { availableContextualOrder = (item, Tags.UnignoreThis); }
1869 DrawSideIcon(deconstructOrder.SymbolSprite,
Direction.Right, TextManager.Get(
"tooltip.markedfordeconstruction"), GUIStyle.Red, out
bool mouseOn);
1870 if (mouseOn) { availableContextualOrder = (item, Tags.DontDeconstructThis); }
1879 maxStackSize = Math.Min(maxStackSize, itemInventory.Container.GetMaxStackSize(slotIndex));
1881 if (maxStackSize > 1 && inventory !=
null)
1883 int itemCount = slot.
MouseOn() ? inventory.slots[slotIndex].Items.Count : inventory.slots[slotIndex].Items.Where(it => !
DraggingItems.Contains(it)).Count();
1886 Vector2 stackCountPos =
new Vector2(rect.Right, rect.Bottom);
1887 string stackCountText =
"x" + itemCount;
1888 stackCountPos -= GUIStyle.SmallFont.MeasureString(stackCountText) +
new Vector2(4, 2);
1889 GUIStyle.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos + Vector2.One, Color.Black);
1890 GUIStyle.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, Color.White);
1894 if (HealingCooldown.IsOnCooldown && item.
HasTag(Tags.MedicalItem))
1896 RectangleF cdRect = rect;
1898 cdRect.Height *= HealingCooldown.NormalizedCooldown;
1899 cdRect.Y += rect.Height;
1900 GUI.DrawFilledRectangle(spriteBatch, cdRect, Color.White * 0.5f);
1904 if (inventory !=
null &&
1905 !inventory.Locked &&
1908 slot.
InventoryKeyIndex < GameSettings.CurrentConfig.InventoryKeyMap.Bindings.Length)
1912 GUIStyle.HotkeyFont.DrawString(
1914 GameSettings.CurrentConfig.InventoryKeyMap.Bindings[slot.
InventoryKeyIndex].Name,
1915 rect.Location.ToVector2() +
new Vector2((
int)(4.25f *
UIScale), (
int)Math.Ceiling(-1.5f *
UIScale)),
1918 origin: Vector2.Zero,
1919 scale: Vector2.One * GUI.AspectRatioAdjustment,
1926 Vector2 iconSize =
new Vector2(25 * GUI.Scale);
1927 float margin = 0.2f;
1928 Vector2 pos =
new Vector2(
1929 side ==
Direction.Left ? rect.X + iconSize.X * margin : rect.Right - iconSize.X * margin,
1930 rect.Bottom - iconSize.Y * 1.2f);
1934 slotIconTooltip = tooltip;
1935 color = Color.Lerp(color, Color.White, 0.5f);
1937 icon.
Draw(spriteBatch, pos, color: color, scale: iconSize.X / icon.
size.X);
1942 private static void DrawItemStateIndicator(
1943 SpriteBatch spriteBatch,
Inventory inventory,
1944 Sprite indicatorSprite,
Sprite emptyIndicatorSprite, Rectangle containedIndicatorArea,
float containedState,
1945 bool pulsate =
false)
1947 Color backgroundColor = GUIStyle.ColorInventoryBackground;
1949 if (indicatorSprite ==
null)
1951 containedIndicatorArea.Inflate(0, -2);
1952 GUI.DrawRectangle(spriteBatch, containedIndicatorArea, backgroundColor,
true);
1953 GUI.DrawRectangle(spriteBatch,
1954 new Rectangle(containedIndicatorArea.X, containedIndicatorArea.Y, (
int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Height),
1955 ToolBox.GradientLerp(containedState, GUIStyle.ColorInventoryEmpty, GUIStyle.ColorInventoryHalf, GUIStyle.ColorInventoryFull) * 0.8f,
true);
1956 GUI.DrawLine(spriteBatch,
1957 new Vector2(containedIndicatorArea.X + (
int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Y),
1958 new Vector2(containedIndicatorArea.X + (
int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Bottom),
1959 Color.Black * 0.8f);
1963 float indicatorScale = Math.Min(
1964 containedIndicatorArea.Width / (
float)indicatorSprite.
SourceRect.Width,
1965 containedIndicatorArea.Height / (
float)indicatorSprite.
SourceRect.Height);
1969 indicatorScale += ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) * 0.2f;
1972 indicatorSprite.
Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
1973 (inventory !=
null && inventory.Locked) ? backgroundColor * 0.5f : backgroundColor,
1974 origin: indicatorSprite.
size / 2,
1976 scale: indicatorScale);
1978 if (containedState > 0.0f)
1980 Color indicatorColor = ToolBox.GradientLerp(containedState, GUIStyle.ColorInventoryEmpty, GUIStyle.ColorInventoryHalf, GUIStyle.ColorInventoryFull);
1981 if (inventory !=
null && inventory.Locked) { indicatorColor *= 0.5f; }
1983 spriteBatch.Draw(indicatorSprite.
Texture, containedIndicatorArea.Center.ToVector2(),
1985 color: indicatorColor,
1987 origin: indicatorSprite.
size / 2,
1988 scale: indicatorScale,
1989 effects: SpriteEffects.None, layerDepth: 0.0f);
1991 spriteBatch.Draw(indicatorSprite.
Texture, containedIndicatorArea.Center.ToVector2(),
1992 sourceRectangle:
new Rectangle(indicatorSprite.
SourceRect.X - 1 + (
int)(indicatorSprite.
SourceRect.Width * containedState), indicatorSprite.
SourceRect.Y, Math.Max((
int)Math.Ceiling(1 / indicatorScale), 2), indicatorSprite.
SourceRect.Height),
1995 origin:
new Vector2(indicatorSprite.
size.X * (0.5f - containedState), indicatorSprite.
size.Y * 0.5f),
1996 scale: indicatorScale,
1997 effects: SpriteEffects.None, layerDepth: 0.0f);
1999 else if (emptyIndicatorSprite !=
null)
2001 Color indicatorColor = GUIStyle.ColorInventoryEmptyOverlay;
2002 if (inventory !=
null && inventory.Locked) { indicatorColor *= 0.5f; }
2004 emptyIndicatorSprite.
Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
2006 origin: emptyIndicatorSprite.
size / 2,
2008 scale: indicatorScale);
2016 partialReceivedItemIDs ??=
new List<ushort>[
capacity];
2017 SharedRead(msg, partialReceivedItemIDs, out
bool readyToApply);
2018 if (!readyToApply) {
return; }
2020 receivedItemIDs = partialReceivedItemIDs.ToArray();
2021 partialReceivedItemIDs =
null;
2029 if (syncItemsCoroutine !=
null) CoroutineManager.StopCoroutines(syncItemsCoroutine);
2030 syncItemsCoroutine = CoroutineManager.StartCoroutine(SyncItemsAfterDelay(lastEventID));
2034 if (syncItemsCoroutine !=
null)
2036 CoroutineManager.StopCoroutines(syncItemsCoroutine);
2037 syncItemsCoroutine =
null;
2043 private IEnumerable<CoroutineStatus> SyncItemsAfterDelay(UInt16 lastEventID)
2056 yield
return CoroutineStatus.Running;
2061 yield
return CoroutineStatus.Success;
2066 yield
return CoroutineStatus.Success;
2075 foreach (
Item item
in slots[i].Items.ToList())
2085 for (
int i =
capacity - 1; i >= 0; i--)
2087 if (!receivedItemIDs[i].
Any()) {
continue; }
2088 foreach (UInt16
id in receivedItemIDs[i])
2097 thisItem.Drop(
null);
2100 if (!
TryPutItem(item, i,
false,
false,
null,
false))
2106 catch (InvalidOperationException e)
2108 DebugConsole.AddSafeError(e.Message +
"\n" + e.StackTrace.CleanupStackTrace());
2121 receivedItemIDs =
null;
bool Freeze
Resets to false each time the MoveCamera method is called.
float GetZoomAmountFromPrevious()
bool??????? ShowCampaignUI
static bool MouseOnCharacterPortrait()
static CharacterHealth?? OpenHealthWindow
bool HasSelectedAnyItem
Has the characters selected a primary or a secondary item?
CharacterHealth CharacterHealth
bool CanInteractWith(Character c, float maxDist=200.0f, bool checkVisibility=true, bool skipDistanceCheck=false)
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...
Character SelectedCharacter
CharacterInventory Inventory
static Character? Controlled
Character FocusedCharacter
bool IsInventoryAccessibleTo(Character character, CharacterInventory.AccessLevel accessLevel=CharacterInventory.AccessLevel.Limited)
Is the inventory accessible to the character? Doesn't check if the character can actually interact wi...
static Dictionary< InvSlotType, Sprite >? LimbSlotIcons
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
bool CanBeAutoMovedToCorrectSlots(Item item)
static readonly List< InvSlotType > AnySlot
static CoroutineStatus Running
static CoroutineStatus Success
void OpenCommandUI(Entity entityContext=null, bool forceContextual=false)
void SetCharacterOrder(Character character, Order order, bool isNewOrder=true)
Sets the character's current order (if it's close enough to receive messages from orderGiver) and dis...
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
void DrawToolTip(SpriteBatch spriteBatch)
Creates and draws a tooltip.
static GameSession?? GameSession
static RasterizerState ScissorTestEnable
static SubEditorScreen SubEditorScreen
static int GraphicsHeight
static GameScreen GameScreen
IReadOnlyList< Item > Items
Item RemoveItem()
Removes one item from the slot
int tooltipDisplayedCondition
bool TooltipNeedsRefresh()
readonly Inventory ParentInventory
SlotReference(Inventory parentInventory, VisualSlot slot, int slotIndex, bool isSubSlot, Inventory subInventory=null)
bool tooltipShowedContextualOptions
virtual void CreateSlots()
static bool IsMouseOnInventory
static Inventory DraggingInventory
bool IsInventoryHoverAvailable(Character owner, ItemContainer container)
readonly int capacity
Capacity, or the number of slots in the inventory.
Rectangle BackgroundFrame
readonly ItemSlot[] slots
virtual ItemInventory GetActiveEquippedSubInventory(int slotIndex)
static void DrawToolTip(SpriteBatch spriteBatch, RichString toolTip, Rectangle highlightedSlot)
Item FirstOrDefault()
Return the first item in the inventory, or null if the inventory is empty.
static Sprite SlotSpriteSmall
virtual 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
virtual void Update(float deltaTime, Camera cam, bool subInventory=false)
void SharedRead(IReadMessage msg, List< ushort >[] receivedItemIds, out bool readyToApply)
static void DrawSlot(SpriteBatch spriteBatch, Inventory inventory, VisualSlot slot, Item item, int slotIndex, bool drawItem=true, InvSlotType type=InvSlotType.Any)
static void UpdateDragging()
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
bool Contains(Item item)
Is the item contained in this inventory. Does not recursively check items inside items.
virtual bool HideSlot(int i)
Inventory(Entity owner, int capacity, int slotsPerRow=5)
static SlotReference selectedSlot
void UpdateSubInventory(float deltaTime, int slotIndex, Camera cam)
static bool IsDragAndDropGiveAllowed
static Sprite DraggableIndicator
static VisualSlot DraggingSlot
List< int > FindIndices(Item item)
Find the indices of all the slots the item is contained in (two-hand items for example can be in mult...
void ClearSubInventories()
virtual void Draw(SpriteBatch spriteBatch, bool subInventory=false)
static bool IsMouseOnSlot(VisualSlot slot)
Check if the mouse is hovering on top of the slot
static readonly List< Item > DraggingItems
Inventory GetReplacementOrThiS()
static int ContainedIndicatorHeight
Inventory GetSubInventory(int slotIndex)
static void RefreshMouseOnInventory()
Refresh the value of IsMouseOnInventory
static Sprite UnequippedIndicator
void DeleteAllItems()
Deletes all items inside the inventory (and also recursively all items inside the items)
int HowManyCanBePut(ItemPrefab itemPrefab, float? condition=null)
Point prevScreenResolution
virtual IEnumerable< Item > AllItems
All items contained in the inventory. Stacked items are returned as individual instances....
void ApplyReceivedState()
virtual void ControlInput(Camera cam)
void ClientEventRead(IReadMessage msg)
static HashSet< SlotReference > highlightedSubInventorySlots
static SlotReference?? SelectedSlot
void ForceToSlot(Item item, int index)
Forces an item to a specific slot. Doesn't remove the item from existing slots/inventories or do any ...
static Sprite slotHotkeySprite
static CursorState GetInventoryMouseCursor()
static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
const float SlotSpriteSmallScale
static bool DraggingItemToWorld
static readonly List< Item > doubleClickedItems
void UpdateSlot(VisualSlot slot, int slotIndex, Item item, bool isSubSlot)
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...
void DrawSubInventory(SpriteBatch spriteBatch, int slotIndex)
virtual void CalculateBackgroundFrame()
Item GetItemAt(int index)
Get the item stored in the specified inventory slot. If the slot contains a stack of items,...
static void DrawFront(SpriteBatch spriteBatch)
bool IsPlayerTeamInteractable
Checks both NonInteractable and NonPlayerTeamInteractable
void Drop(Character dropper, bool createNetworkEvent=true, bool setTransform=true)
ItemInventory OwnInventory
Inventory ParentInventory
IEnumerable< InvSlotType > AllowedSlots
IEnumerable< ItemComponent > ActiveHUDs
bool UseInHealthInterface
Color GetSpriteColor(Color? defaultColor=null, bool withHighlight=false)
Color GetInventoryIconColor()
bool Illegitimate
Item shouldn't be in the player's inventory. If the guards find it, they will consider it as a theft.
bool HasTag(Identifier tag)
override string Name
Note that this is not a LocalizedString instance, just the current name of the item as a string....
float ConditionPercentage
override string ToString()
List< ItemComponent > Components
static HashSet< Item > DeconstructItems
Items that have been marked for deconstruction
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 int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition, bool ignoreItemsInSlot=false)
ImmutableArray< SkillRequirementHint > SkillRequirementHints
int GetMaxStackSize(Inventory inventory)
LocalizedString GetSkillRequirementHints(Character character)
bool HideConditionInTooltip
bool ShowContentsInTooltip
The base class for components holding the different functionalities of the item
virtual void AddTooltipInfo(ref LocalizedString name, ref LocalizedString description)
readonly ItemInventory Inventory
override bool HasRequiredItems(Character character, bool addMessage, LocalizedString msg=null)
override void Move(Vector2 amount, bool ignoreContacts=false)
Sprite InventoryBottomSprite
bool KeepOpenWhenEquippedBy(Character character)
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
readonly ClientEntityEventManager EntityEventManager
static readonly PrefabCollection< OrderPrefab > Prefabs
ContentPackage? ContentPackage
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
static List< AddOrDeleteCommand > BulkItemBuffer
static void StoreCommand(Command command)
static bool IsSubEditor()
static object BulkItemBufferInUse
bool DrawCharacterInventory
static Vector2 MouseDragStart
void MoveBorderHighlight(VisualSlot newSlot)
Moves the current border highlight animation (if one is running) to the new slot
GUIComponent.ComponentState EquipButtonState
Rectangle EquipButtonRect
GUIComponent.ComponentState State
void ShowBorderHighlight(Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount=0.5f)
LocalizedString QuickUseButtonToolTip
VisualSlot(Rectangle rect)
float HighlightScaleUpAmount