装备系统完结,修复并加入很多
This commit is contained in:
@@ -59,7 +59,7 @@ public class UI_Idols : MonoBehaviour
|
||||
public idolDocument ido;
|
||||
public idolSkillsHub ish;
|
||||
public idolSkins isk;
|
||||
public idolWeapon iw;
|
||||
public idolEquipments ieqpmt;
|
||||
public idolUpgrade iu;
|
||||
|
||||
[Header("left toggles")]
|
||||
@@ -87,12 +87,14 @@ public class UI_Idols : MonoBehaviour
|
||||
|
||||
private void Start()
|
||||
{
|
||||
BindQuitButton();
|
||||
InitializeSectionToggles();
|
||||
RebuildCards();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
BindQuitButton();
|
||||
btmandtopController.GlobalOverlayPanelVisibilityChanged += HandleOverlayPanelsVisibilityChanged;
|
||||
AllyHeroDeployLedger.EnsureInstance().OnHeroGrowthChanged += HandleHeroGrowthChanged;
|
||||
InitializeSectionToggles();
|
||||
@@ -102,6 +104,7 @@ public class UI_Idols : MonoBehaviour
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnbindQuitButton();
|
||||
btmandtopController.GlobalOverlayPanelVisibilityChanged -= HandleOverlayPanelsVisibilityChanged;
|
||||
if (AllyHeroDeployLedger.Instance != null)
|
||||
{
|
||||
@@ -115,6 +118,32 @@ public class UI_Idols : MonoBehaviour
|
||||
UnbindSectionToggles();
|
||||
}
|
||||
|
||||
private void BindQuitButton()
|
||||
{
|
||||
if (quitButton == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
quitButton.onClick.RemoveListener(HandleQuitClicked);
|
||||
quitButton.onClick.AddListener(HandleQuitClicked);
|
||||
}
|
||||
|
||||
private void UnbindQuitButton()
|
||||
{
|
||||
if (quitButton == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
quitButton.onClick.RemoveListener(HandleQuitClicked);
|
||||
}
|
||||
|
||||
private void HandleQuitClicked()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void InitializeSectionToggles()
|
||||
{
|
||||
BindSectionToggles();
|
||||
@@ -401,6 +430,11 @@ public class UI_Idols : MonoBehaviour
|
||||
ish.SetHero(hero);
|
||||
}
|
||||
|
||||
if (ieqpmt != null)
|
||||
{
|
||||
ieqpmt.SetHero(hero);
|
||||
}
|
||||
|
||||
if (rightPanel != null)
|
||||
{
|
||||
rightPanel.SetActive(hero != null);
|
||||
@@ -444,7 +478,7 @@ public class UI_Idols : MonoBehaviour
|
||||
SetText(finishGameTimes, FormatSevenDigitCount(hero.ally_finishCount));
|
||||
SetText(mvpGetTimes, FormatSevenDigitCount(hero.ally_mvpCount));
|
||||
SetText(joinTeamTimes, FormatJoinDate(hero.ally_joinDateUtcTicks));
|
||||
ApplyLevelDetails(hero.GetEffectiveLevelForCurrentEXP());
|
||||
ApplyLevelDetails(hero.GetEffectiveLevelInfoWithEquipment(hero.GetEffectiveLevelForCurrentEXP()));
|
||||
ApplyBehaviourRadar(hero);
|
||||
|
||||
PopulateSpecialSkills(hero);
|
||||
@@ -834,12 +868,15 @@ public class UI_Idols : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
SetText(il.hp, levelInfo.maxHP.ToString());
|
||||
SetText(il.attack, levelInfo.attack.ToString());
|
||||
SetText(il.mana, levelInfo.maxMana.ToString());
|
||||
SetText(il.damageResistant, FormatPercent(levelInfo.damageResistance));
|
||||
SetText(il.scoreEfficency, FormatPercent(levelInfo.scoreEfficiency));
|
||||
SetText(il.slotAmount, levelInfo.skill_slot_limited.ToString());
|
||||
AllyHero_SO.AllyLevelInfo baseLevelInfo = currentSelectedHero != null ? currentSelectedHero.GetEffectiveLevelForCurrentEXP() : levelInfo;
|
||||
SetText(il.hp, FormatGrowthInt(baseLevelInfo != null ? baseLevelInfo.maxHP : levelInfo.maxHP, levelInfo.maxHP));
|
||||
SetText(il.attack, FormatGrowthInt(baseLevelInfo != null ? baseLevelInfo.attack : levelInfo.attack, levelInfo.attack));
|
||||
SetText(il.mana, FormatGrowthInt(baseLevelInfo != null ? baseLevelInfo.maxMana : levelInfo.maxMana, levelInfo.maxMana));
|
||||
SetText(il.damageResistant, FormatGrowthPercent(baseLevelInfo != null ? baseLevelInfo.damageResistance : levelInfo.damageResistance, levelInfo.damageResistance));
|
||||
SetText(il.scoreEfficency, FormatGrowthPercent(baseLevelInfo != null ? baseLevelInfo.scoreEfficiency : levelInfo.scoreEfficiency, levelInfo.scoreEfficiency));
|
||||
int baseSlotAmount = baseLevelInfo != null ? baseLevelInfo.skill_slot_limited : levelInfo.skill_slot_limited;
|
||||
int effectiveSlotAmount = currentSelectedHero != null ? currentSelectedHero.GetEffectiveSkillSlotLimit() : levelInfo.skill_slot_limited;
|
||||
SetText(il.slotAmount, FormatGrowthInt(baseSlotAmount, effectiveSlotAmount));
|
||||
SetText(il.miss_mr, levelInfo.manaGainOnMiss.ToString());
|
||||
SetText(il.good_mr, levelInfo.manaGainGood.ToString());
|
||||
SetText(il.great_mr, levelInfo.manaGainGreat.ToString());
|
||||
@@ -850,6 +887,11 @@ public class UI_Idols : MonoBehaviour
|
||||
SetText(il.miss_hl, FormatNumber(levelInfo.missHpLossBase));
|
||||
}
|
||||
|
||||
public void RefreshCurrentHeroDetails()
|
||||
{
|
||||
ApplyHeroDetails(currentSelectedHero, false);
|
||||
}
|
||||
|
||||
private void ApplyBehaviourRadar(AllyHero_SO hero)
|
||||
{
|
||||
if (ido == null || ido.idol_rader == null)
|
||||
@@ -940,6 +982,33 @@ public class UI_Idols : MonoBehaviour
|
||||
return Mathf.RoundToInt(value * 100f) + "%";
|
||||
}
|
||||
|
||||
private static string FormatGrowthInt(int baseValue, int effectiveValue)
|
||||
{
|
||||
int growth = effectiveValue - baseValue;
|
||||
if (growth == 0)
|
||||
{
|
||||
return baseValue.ToString();
|
||||
}
|
||||
|
||||
string sign = growth > 0 ? "+" : "-";
|
||||
string color = growth > 0 ? "#7CFF6B" : "#FF5A5A";
|
||||
return $"{baseValue} <color={color}>{sign} {Mathf.Abs(growth)}</color>";
|
||||
}
|
||||
|
||||
private static string FormatGrowthPercent(float baseValue, float effectiveValue)
|
||||
{
|
||||
float growth = effectiveValue - baseValue;
|
||||
string baseText = FormatPercent(baseValue);
|
||||
if (Mathf.Approximately(growth, 0f))
|
||||
{
|
||||
return baseText;
|
||||
}
|
||||
|
||||
string sign = growth > 0f ? "+" : "-";
|
||||
string color = growth > 0f ? "#7CFF6B" : "#FF5A5A";
|
||||
return $"{baseText} <color={color}>{sign} {FormatPercent(Mathf.Abs(growth))}</color>";
|
||||
}
|
||||
|
||||
private static string FormatNumber(float value)
|
||||
{
|
||||
if (Mathf.Approximately(value, Mathf.Round(value)))
|
||||
|
||||
@@ -0,0 +1,883 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Bansonic;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
public class idolEquipments : MonoBehaviour
|
||||
{
|
||||
private enum EquipFilterMode
|
||||
{
|
||||
All,
|
||||
HasSpecialSkill,
|
||||
HasIllusionSkill,
|
||||
HasAnySkill,
|
||||
HasNoSkill,
|
||||
HasDualSkill,
|
||||
Type0,
|
||||
Type1,
|
||||
Type2,
|
||||
Type3,
|
||||
Type4,
|
||||
Type5,
|
||||
Type6,
|
||||
Type7
|
||||
}
|
||||
|
||||
private enum EquipOrderMode
|
||||
{
|
||||
AcquireAsc,
|
||||
AcquireDesc,
|
||||
QualityAsc,
|
||||
QualityDesc
|
||||
}
|
||||
|
||||
[Header("objects")]
|
||||
public GameObject eqpmtItemPrefab;
|
||||
public Transform eqpmtToPut;
|
||||
|
||||
[Header("INFO")]
|
||||
public Text this_eqpmtName;
|
||||
public Text this_eqpmtType;
|
||||
public Text this_eqpmtLevel;
|
||||
public Text this_eqpmtID;
|
||||
|
||||
[Header("waitingList")]
|
||||
public int i_batch = 16;
|
||||
public Transform eqpmtBagParent;
|
||||
|
||||
[Header("filter")]
|
||||
public Toggle onlyCanEquip;
|
||||
public Dropdown orderFilter;
|
||||
public Dropdown typeFilter;
|
||||
|
||||
[Header("emptyText")]
|
||||
public Text emptyText;
|
||||
public Scrollbar eqpmtBagScrollbar;
|
||||
|
||||
[Header("source paths")]
|
||||
public string runtimeEquipmentFolder = "so/uEquip";
|
||||
public string editorEquipmentFolder = "Assets/Resources/so/uEquip";
|
||||
|
||||
private readonly List<GameObject> spawnedBagItems = new List<GameObject>();
|
||||
private Coroutine rebuildRoutine;
|
||||
private equipmentSO equippedEquipment;
|
||||
private GameObject equippedItemInstance;
|
||||
private AllyHero_SO currentHero;
|
||||
private float pendingScrollbarValue = 1f;
|
||||
private Coroutine restoreScrollbarRoutine;
|
||||
private bool suppressDropdownCallbacks;
|
||||
|
||||
private static readonly (EquipFilterMode mode, string label)[] FilterOptions =
|
||||
{
|
||||
(EquipFilterMode.All, "全部"),
|
||||
(EquipFilterMode.HasSpecialSkill, "含特效技能"),
|
||||
(EquipFilterMode.HasIllusionSkill, "含巡演技能"),
|
||||
(EquipFilterMode.HasAnySkill, "含技能"),
|
||||
(EquipFilterMode.HasNoSkill, "不含技能"),
|
||||
(EquipFilterMode.HasDualSkill, "含双技能"),
|
||||
(EquipFilterMode.Type0, equipmentSO.EquipmentSkillType.题海战术.ToString()),
|
||||
(EquipFilterMode.Type1, equipmentSO.EquipmentSkillType.诛锄异己.ToString()),
|
||||
(EquipFilterMode.Type2, equipmentSO.EquipmentSkillType.逸乐共谋.ToString()),
|
||||
(EquipFilterMode.Type3, equipmentSO.EquipmentSkillType.完美至上.ToString()),
|
||||
(EquipFilterMode.Type4, equipmentSO.EquipmentSkillType.涵养心境.ToString()),
|
||||
(EquipFilterMode.Type5, equipmentSO.EquipmentSkillType.众志成城.ToString()),
|
||||
(EquipFilterMode.Type6, equipmentSO.EquipmentSkillType.过激行为.ToString()),
|
||||
(EquipFilterMode.Type7, equipmentSO.EquipmentSkillType.二次形变.ToString())
|
||||
};
|
||||
|
||||
private static readonly (EquipOrderMode mode, string label)[] OrderOptions =
|
||||
{
|
||||
(EquipOrderMode.AcquireAsc, "获取时间升序"),
|
||||
(EquipOrderMode.AcquireDesc, "获取时间降序"),
|
||||
(EquipOrderMode.QualityAsc, "品质升序"),
|
||||
(EquipOrderMode.QualityDesc, "品质降序")
|
||||
};
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitializeDropdowns();
|
||||
InitializeOnlyCanEquipToggle();
|
||||
BindControls();
|
||||
RestoreEquippedFromHero();
|
||||
RebuildBag();
|
||||
RefreshEquippedSlot();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
InitializeDropdowns();
|
||||
InitializeOnlyCanEquipToggle();
|
||||
BindControls();
|
||||
RestoreEquippedFromHero();
|
||||
RebuildBag();
|
||||
RefreshEquippedSlot();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnbindControls();
|
||||
if (rebuildRoutine != null)
|
||||
{
|
||||
StopCoroutine(rebuildRoutine);
|
||||
rebuildRoutine = null;
|
||||
}
|
||||
|
||||
if (restoreScrollbarRoutine != null)
|
||||
{
|
||||
StopCoroutine(restoreScrollbarRoutine);
|
||||
restoreScrollbarRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void BindControls()
|
||||
{
|
||||
if (onlyCanEquip != null)
|
||||
{
|
||||
onlyCanEquip.onValueChanged.RemoveListener(HandleFilterChanged);
|
||||
onlyCanEquip.onValueChanged.AddListener(HandleFilterChanged);
|
||||
}
|
||||
|
||||
if (orderFilter != null)
|
||||
{
|
||||
orderFilter.onValueChanged.RemoveListener(HandleOrderChanged);
|
||||
orderFilter.onValueChanged.AddListener(HandleOrderChanged);
|
||||
}
|
||||
|
||||
if (typeFilter != null)
|
||||
{
|
||||
typeFilter.onValueChanged.RemoveListener(HandleTypeChanged);
|
||||
typeFilter.onValueChanged.AddListener(HandleTypeChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnbindControls()
|
||||
{
|
||||
if (onlyCanEquip != null)
|
||||
{
|
||||
onlyCanEquip.onValueChanged.RemoveListener(HandleFilterChanged);
|
||||
}
|
||||
|
||||
if (orderFilter != null)
|
||||
{
|
||||
orderFilter.onValueChanged.RemoveListener(HandleOrderChanged);
|
||||
}
|
||||
|
||||
if (typeFilter != null)
|
||||
{
|
||||
typeFilter.onValueChanged.RemoveListener(HandleTypeChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleFilterChanged(bool _)
|
||||
{
|
||||
if (!suppressDropdownCallbacks)
|
||||
{
|
||||
RebuildBag();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleOrderChanged(int _)
|
||||
{
|
||||
if (!suppressDropdownCallbacks)
|
||||
{
|
||||
RebuildBag();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleTypeChanged(int _)
|
||||
{
|
||||
if (!suppressDropdownCallbacks)
|
||||
{
|
||||
RebuildBag();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeDropdowns()
|
||||
{
|
||||
InitializeTypeFilterDropdown();
|
||||
InitializeOrderDropdown();
|
||||
}
|
||||
|
||||
private void InitializeTypeFilterDropdown()
|
||||
{
|
||||
if (typeFilter == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
suppressDropdownCallbacks = true;
|
||||
typeFilter.onValueChanged.RemoveListener(HandleTypeChanged);
|
||||
typeFilter.ClearOptions();
|
||||
typeFilter.AddOptions(FilterOptions.Select(option => new Dropdown.OptionData(option.label)).ToList());
|
||||
typeFilter.value = 0;
|
||||
typeFilter.RefreshShownValue();
|
||||
typeFilter.onValueChanged.AddListener(HandleTypeChanged);
|
||||
suppressDropdownCallbacks = false;
|
||||
}
|
||||
|
||||
private void InitializeOrderDropdown()
|
||||
{
|
||||
if (orderFilter == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
suppressDropdownCallbacks = true;
|
||||
orderFilter.onValueChanged.RemoveListener(HandleOrderChanged);
|
||||
orderFilter.ClearOptions();
|
||||
orderFilter.AddOptions(OrderOptions.Select(option => new Dropdown.OptionData(option.label)).ToList());
|
||||
orderFilter.value = 3;
|
||||
orderFilter.RefreshShownValue();
|
||||
orderFilter.onValueChanged.AddListener(HandleOrderChanged);
|
||||
suppressDropdownCallbacks = false;
|
||||
}
|
||||
|
||||
private void InitializeOnlyCanEquipToggle()
|
||||
{
|
||||
if (onlyCanEquip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
onlyCanEquip.SetIsOnWithoutNotify(true);
|
||||
}
|
||||
|
||||
public void RebuildBag()
|
||||
{
|
||||
CacheScrollbarValue();
|
||||
|
||||
if (rebuildRoutine != null)
|
||||
{
|
||||
StopCoroutine(rebuildRoutine);
|
||||
rebuildRoutine = null;
|
||||
}
|
||||
|
||||
ClearBagItems();
|
||||
|
||||
if (eqpmtItemPrefab == null || eqpmtBagParent == null)
|
||||
{
|
||||
RefreshEmptyState(0);
|
||||
return;
|
||||
}
|
||||
|
||||
List<equipmentSO> equipments = LoadEquipments()
|
||||
.Where(e => e != null)
|
||||
.Where(e => !equipSmelt.IsEquipmentAssignedToSmeltPool(e) && !equipSmelt.ShouldHideConsumedEquipment(e))
|
||||
.Where(e => equippedEquipment == null || e != equippedEquipment)
|
||||
.Where(MatchesCurrentFilters)
|
||||
.ToList();
|
||||
|
||||
SortEquipments(equipments);
|
||||
RefreshEmptyState(equipments.Count);
|
||||
|
||||
if (Application.isPlaying && isActiveAndEnabled && gameObject.activeInHierarchy)
|
||||
{
|
||||
rebuildRoutine = StartCoroutine(RebuildBagAsync(equipments));
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnBagItemsImmediate(equipments);
|
||||
RestoreScrollbarValueImmediate();
|
||||
}
|
||||
|
||||
private IEnumerator RebuildBagAsync(List<equipmentSO> equipments)
|
||||
{
|
||||
int batchSize = Mathf.Max(1, i_batch);
|
||||
for (int i = 0; i < equipments.Count; i++)
|
||||
{
|
||||
SpawnBagItem(equipments[i]);
|
||||
if ((i + 1) % batchSize == 0)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
rebuildRoutine = null;
|
||||
BeginRestoreScrollbarValue();
|
||||
}
|
||||
|
||||
private void SpawnBagItemsImmediate(List<equipmentSO> equipments)
|
||||
{
|
||||
for (int i = 0; i < equipments.Count; i++)
|
||||
{
|
||||
SpawnBagItem(equipments[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnBagItem(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null || eqpmtItemPrefab == null || eqpmtBagParent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject instance = Instantiate(eqpmtItemPrefab, eqpmtBagParent);
|
||||
instance.name = string.IsNullOrWhiteSpace(equipment.GetDisplayTierName()) ? equipment.name : equipment.GetDisplayTierName();
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(equipment, null, HandleBagItemRightClicked);
|
||||
item.allowDrag = false;
|
||||
item.allowQuickTransfer = false;
|
||||
if (item.itemButton != null)
|
||||
{
|
||||
item.itemButton.interactable = true;
|
||||
}
|
||||
}
|
||||
|
||||
spawnedBagItems.Add(instance);
|
||||
}
|
||||
|
||||
private bool HandleBagItemRightClicked(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsEquippedByOtherHero(equipment, out AllyHero_SO occupiedHero))
|
||||
{
|
||||
string heroName = occupiedHero != null ? occupiedHero.ally_heroName : "其他角色";
|
||||
gNotice.warning.display($"该记忆已被{heroName}装备");
|
||||
return true;
|
||||
}
|
||||
|
||||
EquipEquipment(equipment);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquippedItemRightClicked(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null || equippedEquipment == null || equipment != equippedEquipment)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UnequipEquipment();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void EquipEquipment(equipmentSO equipment)
|
||||
{
|
||||
equippedEquipment = equipment;
|
||||
if (currentHero != null)
|
||||
{
|
||||
currentHero.SetEquippedEquipment(equipment);
|
||||
}
|
||||
RefreshAllIdolPanels();
|
||||
RefreshEquippedSlot();
|
||||
RebuildBag();
|
||||
}
|
||||
|
||||
private void UnequipEquipment()
|
||||
{
|
||||
equippedEquipment = null;
|
||||
if (currentHero != null)
|
||||
{
|
||||
currentHero.ClearEquippedEquipment();
|
||||
}
|
||||
RefreshAllIdolPanels();
|
||||
RefreshEquippedSlot();
|
||||
RebuildBag();
|
||||
}
|
||||
|
||||
public void SetHero(AllyHero_SO hero)
|
||||
{
|
||||
currentHero = hero;
|
||||
RestoreEquippedFromHero();
|
||||
RefreshEquippedSlot();
|
||||
RebuildBag();
|
||||
}
|
||||
|
||||
private void RestoreEquippedFromHero()
|
||||
{
|
||||
if (currentHero == null)
|
||||
{
|
||||
equippedEquipment = null;
|
||||
return;
|
||||
}
|
||||
|
||||
currentHero.LoadEquippedEquipmentFromLocal();
|
||||
equippedEquipment = currentHero.GetEquippedEquipmentResolved();
|
||||
}
|
||||
|
||||
private void RefreshEquippedSlot()
|
||||
{
|
||||
if (equippedItemInstance != null)
|
||||
{
|
||||
Destroy(equippedItemInstance);
|
||||
equippedItemInstance = null;
|
||||
}
|
||||
|
||||
if (equippedEquipment != null && eqpmtItemPrefab != null && eqpmtToPut != null)
|
||||
{
|
||||
equippedItemInstance = Instantiate(eqpmtItemPrefab, eqpmtToPut);
|
||||
equippedItemInstance.name = string.IsNullOrWhiteSpace(equippedEquipment.GetDisplayTierName()) ? equippedEquipment.name : equippedEquipment.GetDisplayTierName();
|
||||
|
||||
equipItemPrefab item = equippedItemInstance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(equippedEquipment, null, HandleEquippedItemRightClicked);
|
||||
item.allowDrag = false;
|
||||
item.allowQuickTransfer = false;
|
||||
if (item.itemButton != null)
|
||||
{
|
||||
item.itemButton.interactable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefreshInfoPanel();
|
||||
}
|
||||
|
||||
private void HandleEquipmentClicked(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this_eqpmtName != null)
|
||||
{
|
||||
this_eqpmtName.text = equipment.GetDisplayTierName();
|
||||
this_eqpmtName.color = ResolveEquipmentColor(equipment.GetVisualQualityColorIndex());
|
||||
}
|
||||
|
||||
if (this_eqpmtType != null)
|
||||
{
|
||||
this_eqpmtType.text = $"<b>{equipment.skillType}</b> 类装备";
|
||||
}
|
||||
|
||||
if (this_eqpmtLevel != null)
|
||||
{
|
||||
this_eqpmtLevel.text = $"{equipment.level}追忆等阶";
|
||||
}
|
||||
|
||||
if (this_eqpmtID != null)
|
||||
{
|
||||
this_eqpmtID.text = $"记忆编号{BuildDisplayEquipmentId(equipment)}";
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshInfoPanel()
|
||||
{
|
||||
if (equippedEquipment == null)
|
||||
{
|
||||
if (this_eqpmtName != null)
|
||||
{
|
||||
this_eqpmtName.text = "可装配一个记忆";
|
||||
this_eqpmtName.color = new Color32(0x32, 0x32, 0x32, 0xFF);
|
||||
}
|
||||
if (this_eqpmtType != null) this_eqpmtType.text = "请选择记忆";
|
||||
if (this_eqpmtLevel != null) this_eqpmtLevel.text = string.Empty;
|
||||
if (this_eqpmtID != null) this_eqpmtID.text = "请选择记忆";
|
||||
return;
|
||||
}
|
||||
|
||||
HandleEquipmentClicked(equippedEquipment);
|
||||
}
|
||||
|
||||
private bool IsEquippedByOtherHero(equipmentSO equipment, out AllyHero_SO occupiedHero)
|
||||
{
|
||||
occupiedHero = null;
|
||||
if (equipment == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AllyHero_SO[] heroes = LoadHeroAssetsForOwnershipCheck();
|
||||
for (int i = 0; i < heroes.Length; i++)
|
||||
{
|
||||
AllyHero_SO hero = heroes[i];
|
||||
if (hero == null || hero == currentHero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hero.LoadEquippedEquipmentFromLocal();
|
||||
equipmentSO equipped = hero.GetEquippedEquipmentResolved();
|
||||
if (equipped == equipment || (!string.IsNullOrWhiteSpace(equipped?.name) && equipped.name == equipment.name))
|
||||
{
|
||||
occupiedHero = hero;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private AllyHero_SO[] LoadHeroAssetsForOwnershipCheck()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace("Assets/Resources/so/ally") || !AssetDatabase.IsValidFolder("Assets/Resources/so/ally"))
|
||||
{
|
||||
return Array.Empty<AllyHero_SO>();
|
||||
}
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets("t:AllyHero_SO", new[] { "Assets/Resources/so/ally" });
|
||||
var result = new List<AllyHero_SO>(guids.Length);
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
AllyHero_SO hero = AssetDatabase.LoadAssetAtPath<AllyHero_SO>(path);
|
||||
if (hero != null)
|
||||
{
|
||||
result.Add(hero);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
#endif
|
||||
|
||||
return Resources.LoadAll<AllyHero_SO>("so/ally");
|
||||
}
|
||||
|
||||
private Color ResolveEquipmentColor(int colorIndex)
|
||||
{
|
||||
if (eqpmtItemPrefab == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
equipItemPrefab prefab = eqpmtItemPrefab.GetComponent<equipItemPrefab>();
|
||||
if (prefab == null || prefab.itemBtmColors == null || prefab.itemBtmColors.Length == 0)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
int safeIndex = Mathf.Clamp(colorIndex, 0, prefab.itemBtmColors.Length - 1);
|
||||
return prefab.itemBtmColors[safeIndex];
|
||||
}
|
||||
|
||||
private void RefreshEmptyState(int count)
|
||||
{
|
||||
if (emptyText != null)
|
||||
{
|
||||
emptyText.text = count > 0 ? string.Empty : "暂无装备";
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshAllIdolPanels()
|
||||
{
|
||||
UI_Idols[] panels = FindObjectsByType<UI_Idols>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
for (int i = 0; i < panels.Length; i++)
|
||||
{
|
||||
UI_Idols panel = panels[i];
|
||||
if (panel != null)
|
||||
{
|
||||
panel.RefreshCurrentHeroDetails();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearBagItems()
|
||||
{
|
||||
for (int i = eqpmtBagParent != null ? eqpmtBagParent.childCount - 1 : -1; i >= 0; i--)
|
||||
{
|
||||
Transform child = eqpmtBagParent.GetChild(i);
|
||||
if (child != null)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
spawnedBagItems.Clear();
|
||||
}
|
||||
|
||||
private void CacheScrollbarValue()
|
||||
{
|
||||
if (eqpmtBagScrollbar == null)
|
||||
{
|
||||
pendingScrollbarValue = 1f;
|
||||
return;
|
||||
}
|
||||
|
||||
pendingScrollbarValue = eqpmtBagScrollbar.value;
|
||||
}
|
||||
|
||||
private void BeginRestoreScrollbarValue()
|
||||
{
|
||||
if (!Application.isPlaying || !isActiveAndEnabled || !gameObject.activeInHierarchy)
|
||||
{
|
||||
RestoreScrollbarValueImmediate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (restoreScrollbarRoutine != null)
|
||||
{
|
||||
StopCoroutine(restoreScrollbarRoutine);
|
||||
}
|
||||
|
||||
restoreScrollbarRoutine = StartCoroutine(RestoreScrollbarValueNextFrame());
|
||||
}
|
||||
|
||||
private IEnumerator RestoreScrollbarValueNextFrame()
|
||||
{
|
||||
yield return null;
|
||||
Canvas.ForceUpdateCanvases();
|
||||
yield return null;
|
||||
Canvas.ForceUpdateCanvases();
|
||||
RestoreScrollbarValueImmediate();
|
||||
restoreScrollbarRoutine = null;
|
||||
}
|
||||
|
||||
private void RestoreScrollbarValueImmediate()
|
||||
{
|
||||
if (eqpmtBagScrollbar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ScrollRect scrollRect = eqpmtBagScrollbar.GetComponentInParent<ScrollRect>();
|
||||
if (scrollRect != null && scrollRect.verticalScrollbar == eqpmtBagScrollbar)
|
||||
{
|
||||
scrollRect.verticalNormalizedPosition = pendingScrollbarValue;
|
||||
}
|
||||
|
||||
eqpmtBagScrollbar.value = pendingScrollbarValue;
|
||||
}
|
||||
|
||||
private bool MatchesCurrentFilters(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (onlyCanEquip != null && onlyCanEquip.isOn && !IsEquipmentUsableByCurrentHero(equipment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EquipFilterMode mode = GetSelectedFilterMode();
|
||||
bool hasSpecialSkill = equipment.sa_skillID > 0;
|
||||
bool hasIllusionSkill = equipment.ia_skillID > 0;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case EquipFilterMode.All:
|
||||
return true;
|
||||
case EquipFilterMode.HasSpecialSkill:
|
||||
return hasSpecialSkill;
|
||||
case EquipFilterMode.HasIllusionSkill:
|
||||
return hasIllusionSkill;
|
||||
case EquipFilterMode.HasAnySkill:
|
||||
return hasSpecialSkill || hasIllusionSkill;
|
||||
case EquipFilterMode.HasNoSkill:
|
||||
return !hasSpecialSkill && !hasIllusionSkill;
|
||||
case EquipFilterMode.HasDualSkill:
|
||||
return hasSpecialSkill && hasIllusionSkill;
|
||||
case EquipFilterMode.Type0:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.题海战术;
|
||||
case EquipFilterMode.Type1:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.诛锄异己;
|
||||
case EquipFilterMode.Type2:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.逸乐共谋;
|
||||
case EquipFilterMode.Type3:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.完美至上;
|
||||
case EquipFilterMode.Type4:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.涵养心境;
|
||||
case EquipFilterMode.Type5:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.众志成城;
|
||||
case EquipFilterMode.Type6:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.过激行为;
|
||||
case EquipFilterMode.Type7:
|
||||
return equipment.skillType == equipmentSO.EquipmentSkillType.二次形变;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsEquipmentUsableByCurrentHero(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null || currentHero == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (equipment.GetVisualTierPresentation() == null || string.IsNullOrWhiteSpace(equipment.GetDisplayTierName()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !IsEquippedByOtherHero(equipment, out _);
|
||||
}
|
||||
|
||||
private void SortEquipments(List<equipmentSO> equipments)
|
||||
{
|
||||
if (equipments == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EquipOrderMode mode = GetSelectedOrderMode();
|
||||
switch (mode)
|
||||
{
|
||||
case EquipOrderMode.AcquireAsc:
|
||||
equipments.Sort((a, b) => CompareAcquire(a, b, false));
|
||||
break;
|
||||
case EquipOrderMode.AcquireDesc:
|
||||
equipments.Sort((a, b) => CompareAcquire(a, b, true));
|
||||
break;
|
||||
case EquipOrderMode.QualityAsc:
|
||||
equipments.Sort((a, b) => CompareQuality(a, b, false));
|
||||
break;
|
||||
case EquipOrderMode.QualityDesc:
|
||||
equipments.Sort((a, b) => CompareQuality(a, b, true));
|
||||
break;
|
||||
default:
|
||||
equipments.Sort((a, b) => CompareAcquire(a, b, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private EquipFilterMode GetSelectedFilterMode()
|
||||
{
|
||||
int index = typeFilter != null ? Mathf.Clamp(typeFilter.value, 0, FilterOptions.Length - 1) : 0;
|
||||
return FilterOptions[index].mode;
|
||||
}
|
||||
|
||||
private EquipOrderMode GetSelectedOrderMode()
|
||||
{
|
||||
int index = orderFilter != null ? Mathf.Clamp(orderFilter.value, 0, OrderOptions.Length - 1) : 0;
|
||||
return OrderOptions[index].mode;
|
||||
}
|
||||
|
||||
private equipmentSO[] LoadEquipments()
|
||||
{
|
||||
var results = new List<equipmentSO>();
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
results.AddRange(LoadEditorEquipments());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
results.AddRange(Resources.LoadAll<equipmentSO>(runtimeEquipmentFolder).Where(e => e != null));
|
||||
}
|
||||
|
||||
IReadOnlyList<equipmentSO> runtimeGenerated = equipmentGenerator.GetRuntimeGeneratedEquipments();
|
||||
if (runtimeGenerated != null)
|
||||
{
|
||||
for (int i = 0; i < runtimeGenerated.Count; i++)
|
||||
{
|
||||
equipmentSO equipment = runtimeGenerated[i];
|
||||
if (equipment != null && !results.Contains(equipment))
|
||||
{
|
||||
results.Add(equipment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private static int CompareAcquire(equipmentSO left, equipmentSO right, bool descending)
|
||||
{
|
||||
ParseEquipmentSortKey(left, out long leftDate, out long leftId);
|
||||
ParseEquipmentSortKey(right, out long rightDate, out long rightId);
|
||||
|
||||
int dateCompare = leftDate.CompareTo(rightDate);
|
||||
if (dateCompare != 0)
|
||||
{
|
||||
return descending ? -dateCompare : dateCompare;
|
||||
}
|
||||
|
||||
int idCompare = leftId.CompareTo(rightId);
|
||||
if (idCompare != 0)
|
||||
{
|
||||
return descending ? -idCompare : idCompare;
|
||||
}
|
||||
|
||||
string leftName = left != null ? left.GetDisplayTierName() : string.Empty;
|
||||
string rightName = right != null ? right.GetDisplayTierName() : string.Empty;
|
||||
int nameCompare = string.Compare(leftName, rightName, StringComparison.Ordinal);
|
||||
return descending ? -nameCompare : nameCompare;
|
||||
}
|
||||
|
||||
private static int CompareQuality(equipmentSO left, equipmentSO right, bool descending)
|
||||
{
|
||||
int qualityCompare = left.GetVisualQualityColorIndex().CompareTo(right.GetVisualQualityColorIndex());
|
||||
if (qualityCompare != 0)
|
||||
{
|
||||
return descending ? -qualityCompare : qualityCompare;
|
||||
}
|
||||
|
||||
return CompareAcquire(left, right, true);
|
||||
}
|
||||
|
||||
private static void ParseEquipmentSortKey(equipmentSO equipment, out long datePart, out long idPart)
|
||||
{
|
||||
datePart = 0L;
|
||||
idPart = 0L;
|
||||
|
||||
if (equipment == null || string.IsNullOrWhiteSpace(equipment.name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string raw = equipment.name;
|
||||
if (raw.StartsWith("type", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
int firstUnderscore = raw.IndexOf('_');
|
||||
if (firstUnderscore >= 0 && firstUnderscore + 1 < raw.Length)
|
||||
{
|
||||
raw = raw.Substring(firstUnderscore + 1);
|
||||
}
|
||||
}
|
||||
|
||||
string[] parts = raw.Split('_');
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
long.TryParse(parts[0], out datePart);
|
||||
long.TryParse(parts[1], out idPart);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private equipmentSO[] LoadEditorEquipments()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(editorEquipmentFolder) || !AssetDatabase.IsValidFolder(editorEquipmentFolder))
|
||||
{
|
||||
return Array.Empty<equipmentSO>();
|
||||
}
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets("t:equipmentSO", new[] { editorEquipmentFolder });
|
||||
var result = new List<equipmentSO>(guids.Length);
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
equipmentSO equipment = AssetDatabase.LoadAssetAtPath<equipmentSO>(path);
|
||||
if (equipment != null)
|
||||
{
|
||||
result.Add(equipment);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
#endif
|
||||
|
||||
private static string BuildDisplayEquipmentId(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null || string.IsNullOrWhiteSpace(equipment.name))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string raw = equipment.name.Replace("(Clone)", string.Empty).Replace("(Preview)", string.Empty).Replace("(TourPreview)", string.Empty);
|
||||
return raw.StartsWith("type", StringComparison.OrdinalIgnoreCase) && raw.Length > 4 ? raw.Substring(4) : raw;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c2884ea76fe5ad43a42c2a110586df7
|
||||
@@ -57,8 +57,7 @@ public class idolSkillsHub : MonoBehaviour
|
||||
currentHero.LoadEquippedSkillsFromLocal();
|
||||
|
||||
int currentTierNumber = GetCurrentTierNumber(currentHero);
|
||||
AllyHero_SO.AllyLevelInfo currentLevelInfo = currentHero.GetEffectiveLevelForCurrentEXP();
|
||||
int maxSkillSlots = currentLevelInfo != null ? Mathf.Max(0, currentLevelInfo.skill_slot_limited) : 0;
|
||||
int maxSkillSlots = currentHero.GetEffectiveSkillSlotLimit();
|
||||
|
||||
for (int i = 0; i < currentHero.skillGroups.Length; i++)
|
||||
{
|
||||
@@ -164,8 +163,7 @@ public class idolSkillsHub : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
AllyHero_SO.AllyLevelInfo currentLevelInfo = currentHero.GetEffectiveLevelForCurrentEXP();
|
||||
int maxSkillSlots = currentLevelInfo != null ? Mathf.Max(0, currentLevelInfo.skill_slot_limited) : 0;
|
||||
int maxSkillSlots = currentHero.GetEffectiveSkillSlotLimit();
|
||||
if (equipped.Count >= maxSkillSlots)
|
||||
{
|
||||
Rebuild();
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class idolWeapon : MonoBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec553633425055d4399ed3514af6e3c1
|
||||
@@ -1456,7 +1456,6 @@ public class idolUpgrade : MonoBehaviour
|
||||
List<string> others = recipientSummaries.GetRange(1, recipientSummaries.Count - 1);
|
||||
return string.Format("雨露均沾生效:{0};同时为{1}提供经验", primary, string.Join(",", others.ToArray()));
|
||||
}
|
||||
|
||||
private static string GetPendingDebtKey(int heroId)
|
||||
{
|
||||
return "idol_upgrade_pending_debt_" + heroId;
|
||||
|
||||
@@ -51,6 +51,15 @@ public class materialPrefab : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public void BindOwnedRequired(Sprite sprite, string displayName, int ownedAmount, int requiredAmount, bool selected, bool interactable, Action onClick)
|
||||
{
|
||||
string ownedText = ownedAmount < requiredAmount
|
||||
? $"<color=#FF4D4D>{Mathf.Max(0, ownedAmount)}</color>"
|
||||
: Mathf.Max(0, ownedAmount).ToString();
|
||||
string amountText = $"{ownedText}/{Mathf.Max(0, requiredAmount)}";
|
||||
Bind(sprite, displayName, amountText, selected, interactable, onClick);
|
||||
}
|
||||
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
if (boarder != null)
|
||||
|
||||
Reference in New Issue
Block a user