using Invector; using Invector.vItemManager; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; namespace Beyond { [System.Serializable] public class OnHandleSlot : UnityEngine.Events.UnityEvent { } [System.Serializable] public class OnCompleteSlotList : UnityEngine.Events.UnityEvent> { } [vClassHeader("Item Window", openClose = false)] public class bItemWindow : vMonoBehaviour { [vReadOnly] public bItem currentItem; private List items; public bItemSlot slotPrefab; public RectTransform contentWindow; public List slots; public List supportedItems; public bool updateSlotCount = true; public TMP_Text displayNameText; public Image rarityImage; public Text displayTypeText; public Text displayAmountText; public TMP_Text displayDescriptionText, changeableAttributesText; public Image powerSwordImage; public Text displayAttributesText; public Image displayItemImage, secondaryItemImage, teriaryItemImage; [SerializeField] private Sprite defaultSprite; [Header("Additional things")] public bItemSlot currentSelectedSlot; [SerializeField] private TMP_Text submitButtonText, consumeButtonText; [SerializeField] private RectTransform descriptionTransform; [SerializeField] private Scrollbar descriptionScroolbar; [SerializeField] private string useButtonString = ""; [SerializeField] private GameObject button, consumeButton; [SerializeField] private bool isTradeWindow = false; [vHelpBox("You can ignore display Attributes using this property")] public List ignoreAttributes; [vEditorToolbar("Text Events")] public InputField.OnChangeEvent onChangeName; public InputField.OnChangeEvent onChangeType; public InputField.OnChangeEvent onChangeAmount; public InputField.OnChangeEvent onChangeDescription; public InputField.OnChangeEvent onChangeAttributes; // public InputField.OnChangeEvent onChangeImage; [vEditorToolbar("Events")] public OnCompleteSlotList onCompleteSlotListCallBack; public OnHandleSlot onSubmitSlot; public OnHandleSlot onSelectSlot; public UnityEvent onCancelSlot; [Tooltip("Called when item window has slots on enable")] public UnityEvent onAddSlots; [Tooltip("Called when item window dont have slots on enable")] public UnityEvent onClearSlots; private UnityAction onSubmitSlotCallback; private UnityAction onSelectCallback; private readonly WaitForEndOfFrame WaitForEndOfFrame = new WaitForEndOfFrame(); private List chroniclesTypes = new List { bItemType.ChronicleResources, bItemType.Locations, bItemType.Science, bItemType.Characters }; private void OnEnable() { if (descriptionScroolbar) { StartCoroutine(RebuildLayoutCoroutine()); } } private void OnDisable() { //unload stuff UnloadCurrentImage(); } private void UnloadCurrentImage() { // Sprite spriteToUnload = displayItemImage.sprite; if (displayItemImage) { Resources.UnloadAsset(displayItemImage.sprite); } if (secondaryItemImage) { Resources.UnloadAsset(secondaryItemImage.sprite); } if (teriaryItemImage) { Resources.UnloadAsset(teriaryItemImage.sprite); } if (powerSwordImage) { Resources.UnloadAsset(powerSwordImage.sprite); } // displayItemImage.sprite = null; // secondaryItemImage.sprite = null; // teriaryItemImage.sprite = null; // Resources.UnloadAsset(spriteToUnload); //Resources.UnloadUnusedAssets(); } public void ReloadItems() { ReloadItems(items); } public void ClearSlots() { int slotsCount = slots.Count; for (int i = 0; i < slotsCount; i++) { Destroy(slots[i].gameObject); } slots.Clear(); currentSelectedSlot = null; } public void ReloadItems(List items) { int indexOfSlot = slots.Contains(currentSelectedSlot) ? slots.IndexOf(currentSelectedSlot) : 0; for (int i = 0; i < slots.Count; i++) { if (i >= 0 && i < slots.Count) { if (slots[i] != null && (slots[i].item == null || !items.Contains(slots[i].item))) { Destroy(slots[i].gameObject); slots.Remove(slots[i]); if (i == indexOfSlot) { currentSelectedSlot = i - 1 >= 0 ? slots[i - 1] : slots.Count - 1 > 0 ? slots[0] : null; if (currentSelectedSlot != null) CreateFullItemDescription(currentSelectedSlot); } i--; } else if (slots[i] == null) { slots.RemoveAt(i); i--; } } } if (currentSelectedSlot == null || currentSelectedSlot.item == null || slots.Count == 0) { CreateFullItemDescription(null); if (slots.Count == 0) onClearSlots.Invoke(); } else CreateFullItemDescription(currentSelectedSlot); } public virtual void CreateEquipmentWindow(List items, UnityAction onPickUpItemCallBack = null, UnityAction onSelectSlotCallBack = null, bool destroyAdictionSlots = true) { StartCoroutine(CreateEquipmentWindowRoutine(items, onPickUpItemCallBack, onSelectSlotCallBack, destroyAdictionSlots)); } public virtual void CreateEquipmentWindow(List items, List type, bItem currentItem = null, UnityAction onPickUpItemCallback = null, UnityAction onSelectSlotCallBack = null) { this.items = items.FindAll(item => type.Contains(item.type)); List list = new List(); foreach (var bItem in this.items.OrderBy(item => item.type) .ThenBy(item => item.name)) list.Add(bItem); this.items = list; this.currentItem = currentItem; if (!this.currentItem && this.items.Count > 0) { this.currentItem = this.items[0]; } CreateEquipmentWindowNormal(this.items, onPickUpItemCallback, destroyAdictionSlots: true); } public virtual void CreateEquipmentWindowUsable(List items, List type, bItem currentItem = null, UnityAction onPickUpItemCallback = null, UnityAction onSelectSlotCallBack = null) { this.currentItem = currentItem; var _items = items.FindAll(item => type.Contains(item.type)); var _itemsUsable = _items.FindAll(item => item.canBeUsed); CreateEquipmentWindowNormal(_itemsUsable, onPickUpItemCallback, destroyAdictionSlots: true); } public void CreateEquipmentWindowNormal(List items, UnityAction onPickUpItemCallBack = null, UnityAction onSelectSlotCallBack = null, bool destroyAdictionSlots = true) { var _items = supportedItems.Count == 0 ? items : items.FindAll(i => supportedItems.Contains(i.type)); if (_items.Count == 0) { CreateFullItemDescription(null); onClearSlots.Invoke(); if (slots.Count > 0 && destroyAdictionSlots && updateSlotCount) { for (int i = 0; i < slots.Count; i++) { // yield return null; Destroy(slots[i].gameObject); } slots.Clear(); } currentSelectedSlot = null; } else { if (slots.Count > _items.Count && destroyAdictionSlots && updateSlotCount) { int difference = slots.Count - _items.Count; for (int i = 0; i < difference; i++) { // yield return null; Destroy(slots[0].gameObject); slots.RemoveAt(0); } } bool selecItem = false; onSubmitSlotCallback = onPickUpItemCallBack; onSelectCallback = onSelectSlotCallBack; if (slots == null) slots = new List(); var count = items.Count; if (updateSlotCount) { for (int i = 0; i < _items.Count; i++) { bItemSlot slot = null; if (i < slots.Count) { slot = slots[i]; } else { slot = Instantiate(slotPrefab) as bItemSlot; slots.Add(slot); var rectTranform = slot.GetComponent(); rectTranform.SetParent(contentWindow); rectTranform.localPosition = Vector3.zero; rectTranform.localScale = Vector3.one; rectTranform.localRotation = Quaternion.identity; // yield return null; } // slot = slots[i]; slot.AddItem(_items[i]); if (slot.item.type == bItemType.PowerScroll && slot.item.canBeDroped) { slot.TryToMarkAsSpeciallEquipped(); } else { slot.CheckItem(_items[i].isInEquipArea); } slot.onSubmitSlotCallBack = OnSubmit; slot.onSelectSlotCallBack = OnSelect; if (currentItem != null && currentItem == _items[i]) { if (currentSelectedSlot) { currentSelectedSlot.MarkSlotAsDeselected(); } selecItem = true; currentSelectedSlot = slot; OnSelect(slot); } slot.UpdateDisplays(); } } if (slots.Count > 0 && !selecItem) { currentSelectedSlot = slots[0]; //StartCoroutine(SetSelectableHandle(slots[0].gameObject)); } } SetSubmitButton(currentSelectedSlot); if (slots.Count > 0) { onAddSlots.Invoke(); EnableDescriptionObjects(); CreateFullItemDescription(currentSelectedSlot); } else { DisableDescriptionObjects(); } onCompleteSlotListCallBack.Invoke(slots); } public void EnableDescriptionObjects() { displayNameText.enabled = true; descriptionTransform.gameObject.SetActive(true); } public void DisableDescriptionObjects() { displayNameText.enabled = false; descriptionTransform.gameObject.SetActive(false); } protected virtual IEnumerator CreateEquipmentWindowRoutine(List items, UnityAction onPickUpItemCallBack = null, UnityAction onSelectSlotCallBack = null, bool destroyAdictionSlots = true) { var _items = supportedItems.Count == 0 ? items : items.FindAll(i => supportedItems.Contains(i.type)); if (_items.Count == 0) { CreateFullItemDescription(null); onClearSlots.Invoke(); if (slots.Count > 0 && destroyAdictionSlots && updateSlotCount) { for (int i = 0; i < slots.Count; i++) { // yield return null; Destroy(slots[i].gameObject); } slots.Clear(); currentSelectedSlot = null; } } else { if (slots.Count > _items.Count && destroyAdictionSlots && updateSlotCount) { int difference = slots.Count - _items.Count; for (int i = 0; i < difference; i++) { yield return null; Destroy(slots[0].gameObject); slots.RemoveAt(0); } } bool selecItem = false; onSubmitSlotCallback = onPickUpItemCallBack; onSelectCallback = onSelectSlotCallBack; if (slots == null) slots = new List(); var count = items.Count; // if (updateSlotCount) { for (int i = 0; i < _items.Count; i++) { bItemSlot slot = null; if (i < slots.Count) { slot = slots[i]; } else { slot = Instantiate(slotPrefab) as bItemSlot; slots.Add(slot); var rectTranform = slot.GetComponent(); rectTranform.SetParent(contentWindow); rectTranform.localPosition = Vector3.zero; rectTranform.localScale = Vector3.one; // yield return null; } // slot = slots[i]; slot.AddItem(_items[i]); slot.CheckItem(_items[i].isInEquipArea); slot.onSubmitSlotCallBack = OnSubmit; slot.onSelectSlotCallBack = OnSelect; if (currentItem != null && currentItem == _items[i]) { selecItem = true; currentSelectedSlot = slot; SetSelectable(slot.gameObject); } slot.UpdateDisplays(); } } if (slots.Count > 0 && !selecItem) { currentSelectedSlot = slots[0]; StartCoroutine(SetSelectableHandle(slots[0].gameObject)); } } if (slots.Count > 0) { onAddSlots.Invoke(); CreateFullItemDescription(currentSelectedSlot); } onCompleteSlotListCallBack.Invoke(slots); } public virtual IEnumerator SetSelectableHandle(GameObject target) { if (this.enabled) { yield return WaitForEndOfFrame; SetSelectable(target); } } public virtual void SetSelectable(GameObject target) { var pointer = new PointerEventData(EventSystem.current); ExecuteEvents.Execute(EventSystem.current.currentSelectedGameObject, pointer, ExecuteEvents.pointerExitHandler); EventSystem.current.SetSelectedGameObject(target, new BaseEventData(EventSystem.current)); ExecuteEvents.Execute(target, pointer, ExecuteEvents.selectHandler); } public virtual void OnSubmit(bItemSlot slot) { if (ShouldDissalowUseOfScrolls(slot)) { PopupMenuController.Instance.TryToShowPopupMesssage("Skill Required: " + SkillsManager.instance.GetStringNameOf(Skills.MasterOfScrolls)); } else { currentSelectedSlot = slot; onSubmitSlotCallback?.Invoke(slot); SetSubmitButton(slot); onSubmitSlot.Invoke(slot); } } private bool ShouldDissalowUseOfScrolls(bItemSlot slot) { return slot.item.type == bItemType.PowerScroll && SkillsManager.instance.GetSkillLevelOf(Skills.MasterOfScrolls) == 0 && PopupMenuController.Instance != null && !isTradeWindow; } private void SetSubmitButton(bItemSlot slot) { if (!slot) { button.SetActive(false); if (consumeButton) { consumeButton.SetActive(false); } return; } else { button.SetActive(true); } if (useButtonString != "") { submitButtonText.text = useButtonString; return; } bItemType itemType = slot.item.type; switch (itemType) { case bItemType.MeleeWeapon: case bItemType.Swords: case bItemType.Axes: case bItemType.QuantaPower: case bItemType.Gemstones: submitButtonText.text = slot.isChecked ? "Unequip" : "Equip"; break; case bItemType.PowerScroll: if (!slot.item.canBeDroped) { submitButtonText.text = slot.isChecked ? "Unequip" : "Equip"; } else { button.SetActive(false); } break; case bItemType.Builder: submitButtonText.text = "Create"; break; case bItemType.Consumable: case bItemType.ConsumablesFaith: submitButtonText.text = slot.isChecked ? "Unequip" : "Equip"; consumeButton.SetActive(true); consumeButtonText.text = "Consume"; break; /* case bItemType.Gemstones: submitButtonText.text = "Switch Weapon"; consumeButton.SetActive(true); consumeButtonText.text = "Equip"; break; */ case bItemType.Guilts: submitButtonText.text = "Agree"; break; default: button.SetActive(false); if (consumeButton) { consumeButton.SetActive(false); } break; } } public void SetPowerableSwitchSwordImage(bItem selectedPowerableItem) { Resources.UnloadAsset(powerSwordImage.sprite); if (!selectedPowerableItem) { powerSwordImage.enabled = false; } else { powerSwordImage.enabled = true; powerSwordImage.sprite = Resources.Load(selectedPowerableItem.iconPath); } } public void OnSubmit() { OnSubmit(currentSelectedSlot); } public virtual void OnSelect(bItemSlot slot) { if (slot == null || slot.item == null) { return; } if (currentSelectedSlot) { currentSelectedSlot.MarkSlotAsDeselected(); } currentSelectedSlot = slot; slot.MarkSlotAsSelected(); CreateFullItemDescription(slot); onSelectCallback?.Invoke(slot); SetSubmitButton(slot); onSelectSlot.Invoke(slot); } protected virtual void CreateFullItemDescription(bItemSlot slot) { if (!slot) { return; } var _name = slot.item ? slot.item.name : ""; var _rarity = -1; if (ItemIsRarityInterested(slot)) { bItemAttribute rarityAttribute = slot.item.GetItemAttribute(bItemAttributes.Rarity); _rarity = rarityAttribute != null ? rarityAttribute.value : 0; // 0 means ordinary, 1 ancient, 2 mystical } var _description = slot.item ? slot.item.description : ""; var _image = slot.item ? Resources.Load(slot.item.iconPath) /* slot.item.icon */: defaultSprite; var _secondaryImage = slot.item ? Resources.Load(slot.item.secondaryIconPath) : null; var _teriaryImage = slot.item ? Resources.Load(slot.item.teriaryIconPath) : null; var _type = slot.item ? slot.item.ItemTypeText() : ""; var _amount = slot.item ? slot.item.amount.ToString() : ""; var _attributes = slot.item ? slot.item.GetItemAttributesText(ignoreAttributes) : ""; var _power = slot.item ? slot.item.GetItemAttribute(bItemAttributes.Power) : null; var _Damage = slot.item ? slot.item.GetItemAttribute(bItemAttributes.Damage) : null; if (displayNameText) displayNameText.text = _name; onChangeName.Invoke(_name); if (rarityImage && _rarity >= 0) { rarityImage.gameObject.SetActive(true); rarityImage.sprite = slot.raritySprites[_rarity]; } else { rarityImage.gameObject.SetActive(false); } if (displayTypeText) displayTypeText.text = _type; onChangeType.Invoke(_type); if (displayAmountText) displayAmountText.text = _amount; onChangeAmount.Invoke(_amount); if (displayDescriptionText) displayDescriptionText.text = _description; onChangeDescription.Invoke(_description); if (displayAttributesText) displayAttributesText.text = _attributes; onChangeAttributes.Invoke(_attributes); if (chroniclesTypes.Contains(slot.item.type)) { displayItemImage.sprite = (Sprite)_secondaryImage; } else if (displayItemImage) { displayItemImage.sprite = (Sprite)_image; } bItemAttribute yOffsetAttribute = slot.item.GetItemAttribute(bItemAttributes.ImageYDescOffset); bItemAttribute xOffsetAttribute = slot.item.GetItemAttribute(bItemAttributes.ImageXDescOffset); Vector3 imagePosition = displayItemImage.transform.localPosition; float yOffset = 0; float xOffset = 0; if (yOffsetAttribute != null) { yOffset = yOffsetAttribute.value; } if (xOffsetAttribute != null) { xOffset = xOffsetAttribute.value; } displayItemImage.transform.localPosition = new Vector3(xOffset, yOffset, imagePosition.z); if (secondaryItemImage) secondaryItemImage.sprite = _secondaryImage; if (teriaryItemImage) teriaryItemImage.sprite = _teriaryImage; if (slot.item.type == bItemType.Gemstones) { if (powerSwordImage && powerSwordImage.sprite) { powerSwordImage.gameObject.SetActive(true); } else //in case we have no valid weapons for gemstone { powerSwordImage.gameObject.SetActive(false); } // //for gemstones power value is constant changeableAttributesText.gameObject.SetActive(true); changeableAttributesText.text = "+" + _power.value.ToString() + " Quantum Charge"; } else if (_power != null) //powerable weapons { // < color = blue > (+15) Damage //< color = purple > 0 < color = blue > (+30) Spectral Damage changeableAttributesText.gameObject.SetActive(true); changeableAttributesText.text = "" + _power.value.ToString() + "/100 Quantum Charge "; if (_power.value > 0) { changeableAttributesText.text += "\n" + (_Damage.value * 2).ToString() + " Damage" + "\n" + (_Damage.value * 2).ToString() + " Spectral Damage"; } else { changeableAttributesText.text += "\n" + (_Damage.value).ToString() + " Damage" + "\n" + "0" + " Spectral Damage"; } } else { if (changeableAttributesText) { changeableAttributesText.gameObject.SetActive(false); } if (powerSwordImage) { powerSwordImage.gameObject.SetActive(false); } } if (descriptionTransform) { LayoutRebuilder.ForceRebuildLayoutImmediate(descriptionTransform); } } //need to handle equip private static bool ItemIsRarityInterested(bItemSlot slot) { return slot.item && slot.rarityInterestedType.Contains(slot.item.type); } private IEnumerator RebuildLayoutCoroutine() { yield return new WaitForSecondsRealtime(Time.fixedDeltaTime); LayoutRebuilder.ForceRebuildLayoutImmediate(descriptionTransform); } public virtual void OnCancel() { onCancelSlot.Invoke(); } public void BlockAllButGaze(bool b) { BlockSlots(b, 43); } public void BlockSlots(bool block, int exceptionItem) { foreach (var s in slots) { if (block) { if (s.item.id != exceptionItem) { s.Clickable = false; } } else { s.Clickable = true; } } } } }