641 lines
18 KiB
C#
641 lines
18 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
public class eqpmtDesPrefab : MonoBehaviour
|
|
{
|
|
[Header("so")]
|
|
public equipmentSO eSO;
|
|
|
|
[Header("display")]
|
|
public bool displayBasicAttributes = true;
|
|
public bool displaySpecialEffects = true;
|
|
public bool displayTypeSameEffects = true;
|
|
public bool displayIllusionEffects = true;
|
|
public bool displayMaxLevelEffects = true;
|
|
|
|
[Header("btm")]
|
|
public Image eqpmtBtm;
|
|
public Sprite[] eqpmtBtmSprites;
|
|
|
|
[Header("head")]
|
|
public Text eqpmtName;
|
|
public Text eqpmtID;
|
|
public Text eqpmtLevel;
|
|
public Image eqpmtIcon;
|
|
public Image eqpmtPbtm;
|
|
public Color[] profilebtmColor;
|
|
public Text eqpmtDescription;
|
|
|
|
[Header("body")]
|
|
public Text baTitle;
|
|
public Text baDetail;
|
|
public GameObject baSpace;
|
|
public Text saTitle;
|
|
public Text saDetail;
|
|
public GameObject saSpace;
|
|
public Text taTitle;
|
|
public Text taDetail;
|
|
public GameObject taSpace;
|
|
public Text iaTitle;
|
|
public Text iaDetail;
|
|
public GameObject iaSpace;
|
|
public Text mlTitle;
|
|
public Text mlDetail;
|
|
|
|
[Header("objs")]
|
|
public GameObject eqpmtSkillPrefab;
|
|
public Transform sasParent;
|
|
public Transform iasParent;
|
|
public Transform mlsParent;
|
|
|
|
private RectTransform rectTransform;
|
|
private Canvas rootCanvas;
|
|
private Camera uiCamera;
|
|
private bool ignoreCloseUntilClickReleased;
|
|
|
|
private void Awake()
|
|
{
|
|
rectTransform = transform as RectTransform;
|
|
rootCanvas = GetComponentInParent<Canvas>();
|
|
if (rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
uiCamera = rootCanvas.worldCamera;
|
|
}
|
|
}
|
|
|
|
public void Bind(equipmentSO so)
|
|
{
|
|
eSO = so;
|
|
RefreshView();
|
|
}
|
|
|
|
public void IgnoreCloseUntilClickReleased()
|
|
{
|
|
ignoreCloseUntilClickReleased = true;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (eSO == null || rectTransform == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ignoreCloseUntilClickReleased)
|
|
{
|
|
if (Input.GetMouseButton(0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
ignoreCloseUntilClickReleased = false;
|
|
}
|
|
|
|
if (!Input.GetMouseButtonDown(0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, uiCamera))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsClickInsidePopupHierarchy(Input.mousePosition))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Destroy(gameObject);
|
|
}
|
|
|
|
private bool IsClickInsidePopupHierarchy(Vector2 screenPoint)
|
|
{
|
|
if (EventSystem.current == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PointerEventData pointer = new PointerEventData(EventSystem.current)
|
|
{
|
|
position = screenPoint
|
|
};
|
|
var results = new List<RaycastResult>();
|
|
EventSystem.current.RaycastAll(pointer, results);
|
|
for (int i = 0; i < results.Count; i++)
|
|
{
|
|
GameObject target = results[i].gameObject;
|
|
if (target != null && target.transform.IsChildOf(transform))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void RefreshView()
|
|
{
|
|
ClearSkillPrefabs();
|
|
|
|
if (eSO == null)
|
|
{
|
|
ApplyHeader(string.Empty, null, 0, string.Empty);
|
|
ApplyBasicSection(string.Empty, false);
|
|
ApplyEffectSection(saTitle, saDetail, saSpace, sasParent, string.Empty, null, false);
|
|
ApplyEffectSection(taTitle, taDetail, taSpace, null, string.Empty, null, false);
|
|
ApplyEffectSection(iaTitle, iaDetail, iaSpace, iasParent, string.Empty, null, false);
|
|
ApplyEffectSection(mlTitle, mlDetail, null, mlsParent, string.Empty, null, false);
|
|
return;
|
|
}
|
|
|
|
equipmentSO.EquipmentTierPresentation presentation = ResolveTierPresentation(eSO);
|
|
string displayName = presentation != null && !string.IsNullOrWhiteSpace(presentation.tierName)
|
|
? presentation.tierName
|
|
: eSO.name;
|
|
Sprite displaySprite = presentation != null ? presentation.equipmentSprite : null;
|
|
string description = presentation != null ? presentation.tierDescription : string.Empty;
|
|
|
|
ApplyHeader(displayName, displaySprite, GetQualityVisualIndex(eSO.level), description);
|
|
string basicText = BuildBasicAttributesText(eSO);
|
|
ApplyBasicSection(basicText, displayBasicAttributes && !string.IsNullOrWhiteSpace(basicText));
|
|
|
|
string specialText = BuildEffectText(eSO.specialEffects, out int saSkillId);
|
|
bool hasSpecialSkill = HasSkillEffect(eSO.specialEffects);
|
|
ApplyEffectSection(
|
|
saTitle,
|
|
saDetail,
|
|
saSpace,
|
|
sasParent,
|
|
specialText,
|
|
hasSpecialSkill && saSkillId > 0 ? new[] { saSkillId } : null,
|
|
displaySpecialEffects && HasSectionContent(eSO.specialEffects, saSkillId));
|
|
|
|
string typeSameText = BuildEffectText(eSO.typeSameEffects, out _);
|
|
ApplyEffectSection(
|
|
taTitle,
|
|
taDetail,
|
|
taSpace,
|
|
null,
|
|
typeSameText,
|
|
null,
|
|
displayTypeSameEffects && HasSectionContent(eSO.typeSameEffects, 0));
|
|
|
|
string illusionText = BuildEffectText(eSO.illusionEffects, out int iaSkillId);
|
|
bool isTourPreview = IsTourPreviewEquipment(eSO);
|
|
if (isTourPreview)
|
|
{
|
|
illusionText = string.IsNullOrWhiteSpace(illusionText)
|
|
? "<color=#9DFF84>1个随机巡演特效</color>"
|
|
: $"{illusionText}\n<color=#9DFF84>1个随机巡演特效</color>";
|
|
}
|
|
bool hasIllusionSkill = iaSkillId > 0;
|
|
ApplyEffectSection(
|
|
iaTitle,
|
|
iaDetail,
|
|
iaSpace,
|
|
iasParent,
|
|
illusionText,
|
|
hasIllusionSkill ? new[] { iaSkillId } : null,
|
|
displayIllusionEffects && (isTourPreview || HasSectionContent(eSO.illusionEffects, iaSkillId)));
|
|
|
|
string maxLevelText = BuildEffectText(eSO.maxLevelEffects, out _);
|
|
ApplyEffectSection(
|
|
mlTitle,
|
|
mlDetail,
|
|
null,
|
|
mlsParent,
|
|
maxLevelText,
|
|
null,
|
|
displayMaxLevelEffects && HasSectionContent(eSO.maxLevelEffects, 0));
|
|
}
|
|
|
|
private equipmentSO.EquipmentTierPresentation ResolveTierPresentation(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (equipment.tierNameConfig != null &&
|
|
equipment.tierNameConfig.TryGetStagePresentation(equipment.skillType, equipment.GetTierStageIndex(), out equipmentTierNameConfigSO.StagePresentation stage) &&
|
|
stage != null)
|
|
{
|
|
return new equipmentSO.EquipmentTierPresentation
|
|
{
|
|
tierName = stage.tierName,
|
|
equipmentSprite = stage.equipmentSprite,
|
|
tierDescription = stage.tierDescription
|
|
};
|
|
}
|
|
|
|
return equipment.GetCurrentTierPresentation();
|
|
}
|
|
|
|
private void ApplyHeader(string displayName, Sprite displaySprite, int qualityIndex, string description)
|
|
{
|
|
if (eqpmtName != null)
|
|
{
|
|
eqpmtName.text = displayName;
|
|
eqpmtName.color = GetProfileColor(qualityIndex);
|
|
}
|
|
|
|
if (eqpmtID != null)
|
|
{
|
|
eqpmtID.text = BuildDisplayEquipmentId(eSO);
|
|
}
|
|
|
|
if (eqpmtLevel != null)
|
|
{
|
|
eqpmtLevel.text = eSO != null ? Mathf.Max(0, eSO.level).ToString() : string.Empty;
|
|
}
|
|
|
|
if (eqpmtDescription != null)
|
|
{
|
|
eqpmtDescription.text = description;
|
|
}
|
|
|
|
if (eqpmtIcon != null)
|
|
{
|
|
eqpmtIcon.sprite = displaySprite;
|
|
eqpmtIcon.enabled = displaySprite != null;
|
|
}
|
|
|
|
if (eqpmtBtm != null)
|
|
{
|
|
eqpmtBtm.sprite = GetBottomSprite(qualityIndex);
|
|
eqpmtBtm.enabled = eqpmtBtm.sprite != null;
|
|
}
|
|
|
|
if (eqpmtPbtm != null)
|
|
{
|
|
eqpmtPbtm.color = GetProfileColor(qualityIndex);
|
|
}
|
|
}
|
|
|
|
private void ApplyBasicSection(string text, bool active)
|
|
{
|
|
SetGroupActive(baTitle, baDetail, baSpace, null, active);
|
|
if (baDetail != null)
|
|
{
|
|
baDetail.supportRichText = true;
|
|
baDetail.text = text;
|
|
baDetail.gameObject.SetActive(active && !string.IsNullOrWhiteSpace(text));
|
|
}
|
|
}
|
|
|
|
private void ApplyEffectSection(
|
|
Text title,
|
|
Text detail,
|
|
GameObject space,
|
|
Transform skillParent,
|
|
string text,
|
|
int[] skillIds,
|
|
bool active)
|
|
{
|
|
bool hasText = !string.IsNullOrWhiteSpace(text);
|
|
bool hasSkills = skillParent != null && skillIds != null && skillIds.Length > 0;
|
|
bool showGroup = active && (hasText || hasSkills);
|
|
|
|
SetGroupActive(title, detail, space, null, showGroup);
|
|
if (detail != null)
|
|
{
|
|
detail.supportRichText = true;
|
|
detail.text = text;
|
|
detail.gameObject.SetActive(showGroup && hasText);
|
|
}
|
|
|
|
bool showSkillParent = showGroup && hasSkills;
|
|
if (skillParent != null)
|
|
{
|
|
skillParent.gameObject.SetActive(showSkillParent);
|
|
}
|
|
|
|
if (!showSkillParent)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < skillIds.Length; i++)
|
|
{
|
|
SpawnSkillPrefab(skillParent, skillIds[i]);
|
|
}
|
|
}
|
|
|
|
private void SpawnSkillPrefab(Transform parent, int skillId)
|
|
{
|
|
if (eqpmtSkillPrefab == null || parent == null || skillId <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameObject instance = Instantiate(eqpmtSkillPrefab, parent);
|
|
instance.name = $"eqpmtSkill_{skillId}";
|
|
|
|
eqpmtSkillPrefabItem item = instance.GetComponent<eqpmtSkillPrefabItem>();
|
|
if (item != null)
|
|
{
|
|
item.Bind(skillId);
|
|
return;
|
|
}
|
|
|
|
Text[] texts = instance.GetComponentsInChildren<Text>(true);
|
|
for (int i = 0; i < texts.Length; i++)
|
|
{
|
|
if (texts[i] != null)
|
|
{
|
|
texts[i].text = $"Skill {skillId}";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ClearSkillPrefabs()
|
|
{
|
|
ClearChildren(sasParent);
|
|
ClearChildren(iasParent);
|
|
ClearChildren(mlsParent);
|
|
}
|
|
|
|
private static void ClearChildren(Transform parent)
|
|
{
|
|
if (parent == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = parent.childCount - 1; i >= 0; i--)
|
|
{
|
|
Transform child = parent.GetChild(i);
|
|
if (Application.isPlaying)
|
|
{
|
|
Destroy(child.gameObject);
|
|
}
|
|
else
|
|
{
|
|
DestroyImmediate(child.gameObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void SetGroupActive(Text title, Text detail, GameObject space, Transform skillParent, bool active)
|
|
{
|
|
if (title != null)
|
|
{
|
|
title.gameObject.SetActive(active);
|
|
}
|
|
|
|
if (detail != null)
|
|
{
|
|
detail.gameObject.SetActive(active);
|
|
}
|
|
|
|
if (space != null)
|
|
{
|
|
space.SetActive(active);
|
|
}
|
|
|
|
if (skillParent != null)
|
|
{
|
|
skillParent.gameObject.SetActive(active);
|
|
}
|
|
}
|
|
|
|
private bool HasSectionContent(equipmentSO.EquipmentSpecialEffect[] effects, int skillId)
|
|
{
|
|
if (skillId > 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (effects == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < effects.Length; i++)
|
|
{
|
|
if (effects[i] != null &&
|
|
effects[i].effectType != equipmentSO.EquipmentSpecialEffectType.Skill &&
|
|
!Mathf.Approximately(effects[i].value, 0f))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool HasSkillEffect(equipmentSO.EquipmentSpecialEffect[] effects)
|
|
{
|
|
if (effects == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < effects.Length; i++)
|
|
{
|
|
if (effects[i] != null && effects[i].effectType == equipmentSO.EquipmentSpecialEffectType.Skill)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private string BuildBasicAttributesText(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var lines = new List<string>();
|
|
AppendBasicLine(lines, "最大生命", equipment.maxHp);
|
|
AppendBasicLine(lines, "攻击力", equipment.attack);
|
|
AppendBasicLine(lines, "最大法力", equipment.maxMana);
|
|
AppendBasicLine(lines, "伤害减免", equipment.damageResistance);
|
|
AppendBasicLine(lines, "得分效率", equipment.scoreEfficiency);
|
|
return string.Join("\n", lines);
|
|
}
|
|
|
|
private void AppendBasicLine(List<string> lines, string label, equipmentSO.EquipmentStatTuning tuning)
|
|
{
|
|
if (lines == null || tuning == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float baseValue = tuning.basicGain;
|
|
if (Mathf.Approximately(baseValue, 0f))
|
|
{
|
|
return;
|
|
}
|
|
|
|
float levelGain = eSO != null ? Mathf.Max(0, eSO.level) * tuning.cultivationInterval : 0f;
|
|
float total = baseValue + levelGain;
|
|
|
|
if (eSO == null || Mathf.Max(0, eSO.level) <= 0 || Mathf.Approximately(levelGain, 0f))
|
|
{
|
|
lines.Add($"{label}{FormatTotalPercent(baseValue)}");
|
|
return;
|
|
}
|
|
|
|
lines.Add(
|
|
$"{label}{FormatTotalPercent(total)} " +
|
|
$"(<color=#ADD8E6>{FormatComponentPercent(baseValue)}</color>+<color=#F0E68C>{FormatComponentPercent(levelGain)}</color>)");
|
|
}
|
|
|
|
private string BuildEffectText(equipmentSO.EquipmentSpecialEffect[] effects, out int skillId)
|
|
{
|
|
skillId = 0;
|
|
if (effects == eSO?.specialEffects)
|
|
{
|
|
skillId = eSO != null ? eSO.sa_skillID : 0;
|
|
}
|
|
else if (effects == eSO?.illusionEffects)
|
|
{
|
|
skillId = eSO != null ? eSO.ia_skillID : 0;
|
|
}
|
|
|
|
if (effects == null || effects.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var lines = new List<string>();
|
|
for (int i = 0; i < effects.Length; i++)
|
|
{
|
|
equipmentSO.EquipmentSpecialEffect effect = effects[i];
|
|
if (effect == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (effect.effectType == equipmentSO.EquipmentSpecialEffectType.Skill)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (Mathf.Approximately(effect.value, 0f))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
lines.Add($"{GetEffectDisplayName(effect.effectType)}{FormatSignedValue(effect.value)}");
|
|
}
|
|
|
|
return string.Join("\n", lines);
|
|
}
|
|
|
|
private Sprite GetBottomSprite(int qualityIndex)
|
|
{
|
|
if (eqpmtBtmSprites == null || eqpmtBtmSprites.Length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
int safeIndex = Mathf.Clamp(qualityIndex, 0, eqpmtBtmSprites.Length - 1);
|
|
return eqpmtBtmSprites[safeIndex];
|
|
}
|
|
|
|
private Color GetProfileColor(int qualityIndex)
|
|
{
|
|
if (profilebtmColor == null || profilebtmColor.Length == 0)
|
|
{
|
|
return Color.white;
|
|
}
|
|
|
|
int safeIndex = Mathf.Clamp(qualityIndex, 0, profilebtmColor.Length - 1);
|
|
return profilebtmColor[safeIndex];
|
|
}
|
|
|
|
private static int GetQualityVisualIndex(int level)
|
|
{
|
|
if (level >= 20)
|
|
{
|
|
return 5;
|
|
}
|
|
|
|
if (level >= 15)
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
if (level >= 10)
|
|
{
|
|
return 3;
|
|
}
|
|
|
|
if (level >= 5)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
private static string GetEffectDisplayName(equipmentSO.EquipmentSpecialEffectType effectType)
|
|
{
|
|
switch (effectType)
|
|
{
|
|
case equipmentSO.EquipmentSpecialEffectType.MaxHp: return "最大生命";
|
|
case equipmentSO.EquipmentSpecialEffectType.Attack: return "攻击力";
|
|
case equipmentSO.EquipmentSpecialEffectType.MaxMana: return "最大法力";
|
|
case equipmentSO.EquipmentSpecialEffectType.DamageResistance: return "伤害减免";
|
|
case equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency: return "得分效率";
|
|
case equipmentSO.EquipmentSpecialEffectType.HitManaRecovery: return "hit法力恢复";
|
|
case equipmentSO.EquipmentSpecialEffectType.HitDamageMultiplier: return "hit伤害倍率";
|
|
case equipmentSO.EquipmentSpecialEffectType.HpLoseBase: return "hplosebase";
|
|
case equipmentSO.EquipmentSpecialEffectType.Skill: return "技能";
|
|
default: return effectType.ToString();
|
|
}
|
|
}
|
|
|
|
private static string FormatTotalPercent(float value)
|
|
{
|
|
float percent = value * 100f;
|
|
return $"{(percent >= 0f ? "+" : string.Empty)}{percent:0.0}%";
|
|
}
|
|
|
|
private static string FormatComponentPercent(float value)
|
|
{
|
|
float percent = value * 100f;
|
|
return $"{percent:0.0}%";
|
|
}
|
|
|
|
private static string FormatSignedValue(float value)
|
|
{
|
|
return $"{(value >= 0f ? "+" : string.Empty)}{value:0.####}";
|
|
}
|
|
|
|
private static string BuildDisplayEquipmentId(equipmentSO equipment)
|
|
{
|
|
if (equipment == null || string.IsNullOrWhiteSpace(equipment.name))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
string raw = equipment.name;
|
|
bool isPreview = raw.Contains("(Clone)") || raw.Contains("(TourPreview)");
|
|
raw = raw.Replace("(Clone)", string.Empty).Replace("(TourPreview)", string.Empty).Trim();
|
|
if (raw.StartsWith("type"))
|
|
{
|
|
raw = raw.Substring(4);
|
|
}
|
|
|
|
return isPreview ? $"{raw}(Preview)" : raw;
|
|
}
|
|
|
|
private static bool IsTourPreviewEquipment(equipmentSO equipment)
|
|
{
|
|
return equipment != null &&
|
|
!string.IsNullOrWhiteSpace(equipment.name) &&
|
|
equipment.name.Contains("(TourPreview)");
|
|
}
|
|
}
|
|
|