666 lines
18 KiB
C#
666 lines
18 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using Bansonic;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
public class eFinalDream : MonoBehaviour
|
|
{
|
|
[Header("so")]
|
|
public Player_SO playerSO;
|
|
public equipmentSO eqp_p_SO;
|
|
public eUpdate_mtrSO need_mtrSO;
|
|
|
|
[Header("status")]
|
|
public GameObject beforeObj;
|
|
public GameObject toObj;
|
|
public GameObject nextObj;
|
|
|
|
[Header("dropdown")]
|
|
public Dropdown selectFinalBoost;
|
|
|
|
[Header("dragging")]
|
|
public GameObject dragPrev;
|
|
|
|
[Header("transforms")]
|
|
public Transform prevEquip;
|
|
public Transform nextLevelEquip;
|
|
public GameObject eip;
|
|
|
|
[Header("texts")]
|
|
public Text prevText;
|
|
public Text nextText;
|
|
public Text reasonWhy;
|
|
|
|
[Header("materials")]
|
|
public GameObject mtrPrefab;
|
|
public Transform mtrParent;
|
|
public Text mtrInfo;
|
|
|
|
[Header("sprites")]
|
|
public Sprite memoryFragmentSprite;
|
|
public Sprite coinSprite;
|
|
|
|
[Header("button")]
|
|
public Button yesDreamUpButton;
|
|
|
|
private GameObject spawnedPrevInstance;
|
|
private GameObject spawnedNextInstance;
|
|
private equipmentSO previewSO;
|
|
private readonly List<GameObject> spawnedMaterialItems = new List<GameObject>();
|
|
private readonly List<equipmentSO.EquipmentSpecialEffectType> availableFinalBoostTypes = new List<equipmentSO.EquipmentSpecialEffectType>();
|
|
private equipmentSO cachedFinalBoostEquipment;
|
|
private bool suppressFinalBoostCallback;
|
|
|
|
private void Awake()
|
|
{
|
|
InitializeBindings();
|
|
SetDragPreviewVisible(false);
|
|
RefreshAll();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
InitializeBindings();
|
|
SetDragPreviewVisible(false);
|
|
RefreshAll();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (yesDreamUpButton != null)
|
|
{
|
|
yesDreamUpButton.onClick.RemoveListener(HandleYesDreamClicked);
|
|
}
|
|
|
|
if (selectFinalBoost != null)
|
|
{
|
|
selectFinalBoost.onValueChanged.RemoveListener(HandleFinalBoostChanged);
|
|
}
|
|
}
|
|
|
|
private void InitializeBindings()
|
|
{
|
|
if (playerSO != null)
|
|
{
|
|
PlayerEconomyLedger.EnsureInstance().AttachPlayerData(playerSO);
|
|
}
|
|
|
|
if (selectFinalBoost != null)
|
|
{
|
|
selectFinalBoost.onValueChanged.RemoveListener(HandleFinalBoostChanged);
|
|
selectFinalBoost.onValueChanged.AddListener(HandleFinalBoostChanged);
|
|
}
|
|
|
|
if (yesDreamUpButton != null)
|
|
{
|
|
yesDreamUpButton.onClick.RemoveListener(HandleYesDreamClicked);
|
|
yesDreamUpButton.onClick.AddListener(HandleYesDreamClicked);
|
|
}
|
|
}
|
|
|
|
public void SetDragPreviewVisible(bool visible)
|
|
{
|
|
if (dragPrev == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!gameObject.activeInHierarchy)
|
|
{
|
|
dragPrev.SetActive(false);
|
|
return;
|
|
}
|
|
|
|
dragPrev.SetActive(visible);
|
|
}
|
|
|
|
public bool IsPointerOverDropArea(Vector2 screenPoint, Camera eventCamera)
|
|
{
|
|
if (dragPrev == null || !dragPrev.activeInHierarchy)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RectTransform rectTransform = dragPrev.transform as RectTransform;
|
|
if (rectTransform == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return RectTransformUtility.RectangleContainsScreenPoint(rectTransform, screenPoint, eventCamera);
|
|
}
|
|
|
|
public void AcceptDraggedEquipment(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
eqp_p_SO = equipment;
|
|
cachedFinalBoostEquipment = null;
|
|
RefreshAll();
|
|
}
|
|
|
|
private void HandleFinalBoostChanged(int _)
|
|
{
|
|
if (suppressFinalBoostCallback)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RefreshPreviewStateOnly();
|
|
}
|
|
|
|
private void RefreshAll()
|
|
{
|
|
EnsureFinalBoostOptions();
|
|
RefreshPrevPreview();
|
|
RefreshNextPreview();
|
|
RefreshStateObjects();
|
|
RefreshTexts();
|
|
RefreshMaterials();
|
|
RefreshReasonWhy();
|
|
RefreshActionState();
|
|
}
|
|
|
|
private void RefreshPreviewStateOnly()
|
|
{
|
|
RefreshNextPreview();
|
|
RefreshStateObjects();
|
|
RefreshTexts();
|
|
RefreshReasonWhy();
|
|
RefreshActionState();
|
|
}
|
|
|
|
private void RefreshPrevPreview()
|
|
{
|
|
DestroySpawned(ref spawnedPrevInstance);
|
|
|
|
if (eqp_p_SO == null || eip == null || prevEquip == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
spawnedPrevInstance = Instantiate(eip, prevEquip);
|
|
spawnedPrevInstance.name = $"{eqp_p_SO.name}_FinalDreamPrev";
|
|
spawnedPrevInstance.SetActive(true);
|
|
|
|
equipItemPrefab item = spawnedPrevInstance.GetComponent<equipItemPrefab>();
|
|
if (item != null)
|
|
{
|
|
item.Bind(eqp_p_SO);
|
|
item.SetInteractionOptions(false, false);
|
|
}
|
|
}
|
|
|
|
private void RefreshNextPreview()
|
|
{
|
|
DestroySpawned(ref spawnedNextInstance);
|
|
DestroyPreviewEquipment();
|
|
|
|
if (!CanPreview())
|
|
{
|
|
return;
|
|
}
|
|
|
|
previewSO = Instantiate(eqp_p_SO);
|
|
previewSO.name = $"{eqp_p_SO.name}(FinalPreview)";
|
|
ApplyFinalBoost(previewSO, GetSelectedBoostType(), 0.01f);
|
|
|
|
spawnedNextInstance = Instantiate(eip, nextLevelEquip);
|
|
spawnedNextInstance.name = $"{eqp_p_SO.name}_FinalDreamNext";
|
|
spawnedNextInstance.SetActive(true);
|
|
|
|
equipItemPrefab item = spawnedNextInstance.GetComponent<equipItemPrefab>();
|
|
if (item != null)
|
|
{
|
|
item.Bind(previewSO);
|
|
item.SetInteractionOptions(false, false);
|
|
}
|
|
}
|
|
|
|
private void RefreshStateObjects()
|
|
{
|
|
if (beforeObj != null)
|
|
{
|
|
beforeObj.SetActive(true);
|
|
}
|
|
|
|
bool canPreview = CanPreview();
|
|
if (toObj != null)
|
|
{
|
|
toObj.SetActive(canPreview);
|
|
}
|
|
|
|
if (nextObj != null)
|
|
{
|
|
nextObj.SetActive(canPreview);
|
|
}
|
|
}
|
|
|
|
private void RefreshTexts()
|
|
{
|
|
if (prevText != null)
|
|
{
|
|
prevText.text = eqp_p_SO != null ? ResolveEquipmentName(eqp_p_SO) : string.Empty;
|
|
prevText.color = eqp_p_SO != null
|
|
? ResolveEquipmentColor(eqp_p_SO.GetVisualQualityColorIndex())
|
|
: Color.black;
|
|
}
|
|
|
|
if (nextText != null)
|
|
{
|
|
nextText.text = previewSO != null ? ResolveEquipmentName(previewSO) : string.Empty;
|
|
nextText.color = previewSO != null
|
|
? ResolveEquipmentColor(previewSO.GetVisualQualityColorIndex())
|
|
: Color.black;
|
|
}
|
|
}
|
|
|
|
private void RefreshMaterials()
|
|
{
|
|
ClearSpawnedMaterialItems();
|
|
|
|
if (mtrInfo == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string structuralReason = GetStructuralFailureReason();
|
|
if (!string.IsNullOrEmpty(structuralReason))
|
|
{
|
|
mtrInfo.text = structuralReason;
|
|
return;
|
|
}
|
|
|
|
mtrInfo.text = string.Empty;
|
|
SpawnMaterialItems();
|
|
}
|
|
|
|
private void SpawnMaterialItems()
|
|
{
|
|
if (mtrPrefab == null || mtrParent == null || need_mtrSO == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int materialRequired = need_mtrSO.GetFinalDreamMaterialRequired();
|
|
int coinRequired = need_mtrSO.GetFinalDreamCoinsRequired();
|
|
int memoryRequired = need_mtrSO.GetFinalDreamMemoryFragmentRequired();
|
|
|
|
if (materialRequired > 0 && need_mtrSO.finalDreamMaterial != null)
|
|
{
|
|
SpawnMaterialItem(
|
|
need_mtrSO.finalDreamMaterial.consumableSprite,
|
|
need_mtrSO.finalDreamMaterial.consumableName,
|
|
EquipmentConsumableLedger.EnsureInstance().GetCount(need_mtrSO.finalDreamMaterial.consumableKind),
|
|
materialRequired);
|
|
}
|
|
|
|
if (coinRequired > 0)
|
|
{
|
|
SpawnMaterialItem(coinSprite, "算力", PlayerEconomyLedger.EnsureInstance().GetCoins(), coinRequired);
|
|
}
|
|
|
|
if (memoryRequired > 0)
|
|
{
|
|
SpawnMaterialItem(memoryFragmentSprite, "记忆碎片", PlayerEconomyLedger.EnsureInstance().GetMaterial(), memoryRequired);
|
|
}
|
|
}
|
|
|
|
private void SpawnMaterialItem(Sprite sprite, string displayName, int ownedAmount, int requiredAmount)
|
|
{
|
|
GameObject instance = Instantiate(mtrPrefab, mtrParent);
|
|
instance.SetActive(true);
|
|
spawnedMaterialItems.Add(instance);
|
|
|
|
materialPrefab item = instance.GetComponent<materialPrefab>();
|
|
if (item != null)
|
|
{
|
|
item.BindOwnedRequired(sprite, displayName, ownedAmount, requiredAmount, true, false, null);
|
|
item.SetSelected(true);
|
|
if (item.materialButton != null)
|
|
{
|
|
item.materialButton.interactable = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RefreshReasonWhy()
|
|
{
|
|
if (reasonWhy != null)
|
|
{
|
|
reasonWhy.text = GetActionFailureReason();
|
|
}
|
|
}
|
|
|
|
private void RefreshActionState()
|
|
{
|
|
if (yesDreamUpButton != null)
|
|
{
|
|
yesDreamUpButton.interactable = string.IsNullOrEmpty(GetActionFailureReason());
|
|
}
|
|
}
|
|
|
|
private string GetStructuralFailureReason()
|
|
{
|
|
if (eqp_p_SO == null)
|
|
{
|
|
return "需要选择一个记忆";
|
|
}
|
|
|
|
if (eqp_p_SO.level < 0 || eqp_p_SO.level > 20)
|
|
{
|
|
return "非法等级";
|
|
}
|
|
|
|
if (eqp_p_SO.level != 20)
|
|
{
|
|
return "要求20追忆等级";
|
|
}
|
|
|
|
if (need_mtrSO == null)
|
|
{
|
|
return "未配置登顶强化规则";
|
|
}
|
|
|
|
if (need_mtrSO.finalDreamMaterial == null)
|
|
{
|
|
return "未配置登顶材料";
|
|
}
|
|
|
|
if (availableFinalBoostTypes.Count == 0)
|
|
{
|
|
return "当前记忆没有可登顶的基础属性";
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private string GetActionFailureReason()
|
|
{
|
|
string structuralReason = GetStructuralFailureReason();
|
|
if (!string.IsNullOrEmpty(structuralReason))
|
|
{
|
|
return structuralReason;
|
|
}
|
|
|
|
int materialRequired = need_mtrSO.GetFinalDreamMaterialRequired();
|
|
int coinRequired = need_mtrSO.GetFinalDreamCoinsRequired();
|
|
int memoryRequired = need_mtrSO.GetFinalDreamMemoryFragmentRequired();
|
|
|
|
if (materialRequired > 0 && EquipmentConsumableLedger.EnsureInstance().GetCount(need_mtrSO.finalDreamMaterial.consumableKind) < materialRequired)
|
|
{
|
|
return "登顶材料不足";
|
|
}
|
|
|
|
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(coinRequired))
|
|
{
|
|
return "算力不足";
|
|
}
|
|
|
|
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughMaterial(memoryRequired))
|
|
{
|
|
return "记忆碎片不足";
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private void HandleYesDreamClicked()
|
|
{
|
|
string failureReason = GetActionFailureReason();
|
|
if (!string.IsNullOrEmpty(failureReason))
|
|
{
|
|
RefreshAll();
|
|
return;
|
|
}
|
|
|
|
int materialRequired = need_mtrSO.GetFinalDreamMaterialRequired();
|
|
int coinRequired = need_mtrSO.GetFinalDreamCoinsRequired();
|
|
int memoryRequired = need_mtrSO.GetFinalDreamMemoryFragmentRequired();
|
|
|
|
if (materialRequired > 0 && !EquipmentConsumableLedger.EnsureInstance().TryConsume(need_mtrSO.finalDreamMaterial.consumableKind, materialRequired))
|
|
{
|
|
RefreshAll();
|
|
return;
|
|
}
|
|
|
|
if (coinRequired > 0 && !PlayerEconomyLedger.EnsureInstance().TrySpendCoins(coinRequired))
|
|
{
|
|
if (materialRequired > 0)
|
|
{
|
|
EquipmentConsumableLedger.EnsureInstance().Add(need_mtrSO.finalDreamMaterial.consumableKind, materialRequired);
|
|
}
|
|
RefreshAll();
|
|
return;
|
|
}
|
|
|
|
if (memoryRequired > 0 && !PlayerEconomyLedger.EnsureInstance().TrySpendMaterial(memoryRequired))
|
|
{
|
|
if (coinRequired > 0)
|
|
{
|
|
PlayerEconomyLedger.EnsureInstance().AddCoins(coinRequired);
|
|
}
|
|
|
|
if (materialRequired > 0)
|
|
{
|
|
EquipmentConsumableLedger.EnsureInstance().Add(need_mtrSO.finalDreamMaterial.consumableKind, materialRequired);
|
|
}
|
|
RefreshAll();
|
|
return;
|
|
}
|
|
|
|
ApplyFinalBoost(eqp_p_SO, GetSelectedBoostType(), 0.01f);
|
|
PersistEquipment(eqp_p_SO);
|
|
RefreshAllEquipBags();
|
|
RefreshAll();
|
|
}
|
|
|
|
private bool CanPreview()
|
|
{
|
|
return string.IsNullOrEmpty(GetStructuralFailureReason()) &&
|
|
availableFinalBoostTypes.Count > 0 &&
|
|
eip != null &&
|
|
nextLevelEquip != null;
|
|
}
|
|
|
|
private equipmentSO.EquipmentSpecialEffectType GetSelectedBoostType()
|
|
{
|
|
if (availableFinalBoostTypes.Count == 0)
|
|
{
|
|
return equipmentSO.EquipmentSpecialEffectType.MaxHp;
|
|
}
|
|
|
|
int index = selectFinalBoost != null ? Mathf.Clamp(selectFinalBoost.value, 0, availableFinalBoostTypes.Count - 1) : 0;
|
|
return availableFinalBoostTypes[index];
|
|
}
|
|
|
|
private void EnsureFinalBoostOptions()
|
|
{
|
|
if (selectFinalBoost == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (cachedFinalBoostEquipment == eqp_p_SO && selectFinalBoost.options != null && selectFinalBoost.options.Count == availableFinalBoostTypes.Count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int currentValue = selectFinalBoost.value;
|
|
availableFinalBoostTypes.Clear();
|
|
var options = new List<Dropdown.OptionData>(5);
|
|
AppendFinalBoostOption(eqp_p_SO != null && !Mathf.Approximately(eqp_p_SO.maxHp.basicGain, 0f), equipmentSO.EquipmentSpecialEffectType.MaxHp, "最大生命值", options);
|
|
AppendFinalBoostOption(eqp_p_SO != null && !Mathf.Approximately(eqp_p_SO.attack.basicGain, 0f), equipmentSO.EquipmentSpecialEffectType.Attack, "攻击力", options);
|
|
AppendFinalBoostOption(eqp_p_SO != null && !Mathf.Approximately(eqp_p_SO.maxMana.basicGain, 0f), equipmentSO.EquipmentSpecialEffectType.MaxMana, "最大法力值", options);
|
|
AppendFinalBoostOption(eqp_p_SO != null && !Mathf.Approximately(eqp_p_SO.damageResistance.basicGain, 0f), equipmentSO.EquipmentSpecialEffectType.DamageResistance, "伤害减免", options);
|
|
AppendFinalBoostOption(eqp_p_SO != null && !Mathf.Approximately(eqp_p_SO.scoreEfficiency.basicGain, 0f), equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency, "得分效率", options);
|
|
suppressFinalBoostCallback = true;
|
|
selectFinalBoost.ClearOptions();
|
|
selectFinalBoost.AddOptions(options);
|
|
if (options.Count > 0)
|
|
{
|
|
selectFinalBoost.value = Mathf.Clamp(currentValue, 0, options.Count - 1);
|
|
}
|
|
selectFinalBoost.RefreshShownValue();
|
|
suppressFinalBoostCallback = false;
|
|
cachedFinalBoostEquipment = eqp_p_SO;
|
|
}
|
|
|
|
private void AppendFinalBoostOption(bool include, equipmentSO.EquipmentSpecialEffectType effectType, string displayName, List<Dropdown.OptionData> options)
|
|
{
|
|
if (!include)
|
|
{
|
|
return;
|
|
}
|
|
|
|
availableFinalBoostTypes.Add(effectType);
|
|
options.Add(new Dropdown.OptionData(displayName));
|
|
}
|
|
|
|
private static void ApplyFinalBoost(equipmentSO equipment, equipmentSO.EquipmentSpecialEffectType effectType, float boostValue)
|
|
{
|
|
equipment.maxLevelEffects = new[]
|
|
{
|
|
new equipmentSO.EquipmentSpecialEffect
|
|
{
|
|
effectType = effectType,
|
|
value = boostValue
|
|
}
|
|
};
|
|
}
|
|
|
|
private static bool HasMaxLevelEffect(equipmentSO equipment)
|
|
{
|
|
return equipment != null && equipment.maxLevelEffects != null && equipment.maxLevelEffects.Length > 0;
|
|
}
|
|
|
|
private static string ResolveEquipmentName(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
string displayName = equipment.GetDisplayTierName();
|
|
return string.IsNullOrWhiteSpace(displayName) ? equipment.name : displayName;
|
|
}
|
|
|
|
private static Color ResolveEquipmentColor(int colorIndex)
|
|
{
|
|
equipItemPrefab reference = Object.FindFirstObjectByType<equipItemPrefab>(FindObjectsInactive.Include);
|
|
if (reference == null)
|
|
{
|
|
return Color.white;
|
|
}
|
|
|
|
return reference.GetAccentColorByVisualIndex(colorIndex);
|
|
}
|
|
|
|
private void ClearSpawnedMaterialItems()
|
|
{
|
|
if (mtrParent != null)
|
|
{
|
|
for (int i = mtrParent.childCount - 1; i >= 0; i--)
|
|
{
|
|
Transform child = mtrParent.GetChild(i);
|
|
if (child == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
DestroyImmediate(child.gameObject);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
Destroy(child.gameObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
spawnedMaterialItems.Clear();
|
|
}
|
|
|
|
private void DestroySpawned(ref GameObject instance)
|
|
{
|
|
if (instance == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
DestroyImmediate(instance);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
Destroy(instance);
|
|
}
|
|
|
|
instance = null;
|
|
}
|
|
|
|
private void DestroyPreviewEquipment()
|
|
{
|
|
if (previewSO == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
DestroyImmediate(previewSO);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
Destroy(previewSO);
|
|
}
|
|
|
|
previewSO = null;
|
|
}
|
|
|
|
private static void PersistEquipment(equipmentSO equipment)
|
|
{
|
|
if (equipment == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Application.isPlaying)
|
|
{
|
|
equipmentGenerator.SaveRuntimeEquipmentState(equipment);
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
EditorUtility.SetDirty(equipment);
|
|
AssetDatabase.SaveAssets();
|
|
#endif
|
|
}
|
|
|
|
private static void RefreshAllEquipBags()
|
|
{
|
|
equipBag[] bags = UnityEngine.Object.FindObjectsByType<equipBag>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
for (int i = 0; i < bags.Length; i++)
|
|
{
|
|
if (bags[i] != null)
|
|
{
|
|
bags[i].Rebuild();
|
|
}
|
|
}
|
|
}
|
|
}
|