装备系统做了很多
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06b4eade4e6b6dc44ab55308c9b7d7ab
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 51eaa69f0e6f47a48a3391b66f902d8b, type: 3}
|
||||
m_Name: SmeltStageRewardSO
|
||||
m_EditorClassIdentifier:
|
||||
simpleRewardAmount: 40
|
||||
_1skillRewardAmount: 100
|
||||
_2skillRewardAmount: 300
|
||||
quickFinishCost: 200
|
||||
rewardRandomConfig: {fileID: 11400000, guid: ca394ccb04190524fb487491eedb36e7, type: 2}
|
||||
rewardTemplate: {fileID: 11400000, guid: 40fe16e436a81644aa688c80436aa1c1, type: 2}
|
||||
smeltEquipmentCapacity: 60
|
||||
smeltStorageCapacity: 3000
|
||||
rewardRequirements:
|
||||
- equipmentType: 0
|
||||
qualityType: 0
|
||||
skillRequirement: 0
|
||||
chosenSkillType: 0
|
||||
equipRewardName: "40 \u968F\u673A\u8BB0\u5FC6"
|
||||
requiredAmount: 40
|
||||
- equipmentType: 1
|
||||
qualityType: 0
|
||||
skillRequirement: 0
|
||||
chosenSkillType: 0
|
||||
equipRewardName: "60 \u81EA\u9009\u8BB0\u5FC6"
|
||||
requiredAmount: 60
|
||||
- equipmentType: 0
|
||||
qualityType: 0
|
||||
skillRequirement: 0
|
||||
chosenSkillType: 0
|
||||
equipRewardName: "200 \u81EA\u9009\u9AD8\u5929\u8D4B\u8BB0\u5FC6"
|
||||
requiredAmount: 120
|
||||
- equipmentType: 0
|
||||
qualityType: 0
|
||||
skillRequirement: 1
|
||||
chosenSkillType: 0
|
||||
equipRewardName: "500 \u81EA\u9009\u73CD\u85CF\u8BB0\u5FC6"
|
||||
requiredAmount: 500
|
||||
- equipmentType: 1
|
||||
qualityType: 0
|
||||
skillRequirement: 2
|
||||
chosenSkillType: 0
|
||||
equipRewardName: "1000 \u81EA\u9009\u81F3\u81FB\u8BB0\u5FC6"
|
||||
requiredAmount: 1000
|
||||
- equipmentType: 1
|
||||
qualityType: 1
|
||||
skillRequirement: 2
|
||||
chosenSkillType: 0
|
||||
equipRewardName: "1500 \u81EA\u9009\u523B\u9AA8\u94ED\u5FC3\u8BB0\u5FC6"
|
||||
requiredAmount: 1500
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6cd7091184a62c946b093bb0a91deae2
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,832 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Bansonic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
public class equipSmelt : MonoBehaviour
|
||||
{
|
||||
private static readonly List<equipmentSO> SmeltPoolEquipments = new List<equipmentSO>();
|
||||
private static readonly HashSet<equipmentSO> SmeltPoolLookup = new HashSet<equipmentSO>();
|
||||
private static readonly HashSet<equipmentSO> ConsumedSmeltEquipments = new HashSet<equipmentSO>();
|
||||
private static readonly List<equipSmelt> Instances = new List<equipSmelt>();
|
||||
|
||||
private static bool isSmeltingState;
|
||||
private static bool smeltCompletedState;
|
||||
private static int gamesRequiredForCurrentBatchState;
|
||||
private static int gamesCompletedForCurrentBatchState;
|
||||
private static int pendingDirectFragmentsState;
|
||||
private static int pendingStoredFragmentsState;
|
||||
private static int storedSmeltEnergyState;
|
||||
|
||||
[Header("so")]
|
||||
public smeltStageRewardSO ssrso;
|
||||
|
||||
[Header("sprites")]
|
||||
public Sprite memoryFragment;
|
||||
public Sprite coins;
|
||||
|
||||
[Header("selection and progress")]
|
||||
public GameObject smeltPool;
|
||||
public GameObject smeltProgress;
|
||||
|
||||
[Header("drag")]
|
||||
public GameObject dragObj;
|
||||
|
||||
[Header("smeltPool")]
|
||||
public GameObject smeltPoolItemPrefab;
|
||||
public Transform smeltPoolContent;
|
||||
|
||||
[Header("smeltTimeProgress")]
|
||||
public Slider stpSlider;
|
||||
public Text smeltStatusText;
|
||||
public Button quickFinishButton;
|
||||
public Text qf_cost_text;
|
||||
|
||||
[Header("smelt Rewards")]
|
||||
public Text rewardGenProgress;
|
||||
public Image rewardProgressImage;
|
||||
public Dropdown selectAReward;
|
||||
public Button getReward;
|
||||
|
||||
[Header("smelt notice")]
|
||||
public Image d_mf_img;
|
||||
public Text d_mf_Amount;
|
||||
public Image s_mf_img;
|
||||
public Text s_mf_Amount;
|
||||
public Text smeltNoticeText;
|
||||
|
||||
[Header("cost and start")]
|
||||
public Text costText;
|
||||
public Text reasonWhy;
|
||||
public Button startSmeltButton;
|
||||
|
||||
[Header("choose type and skill")]
|
||||
public GameObject ctasPrefab;
|
||||
public Transform ctasParent;
|
||||
|
||||
private readonly List<GameObject> spawnedPoolItems = new List<GameObject>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
RegisterInstance();
|
||||
BindButtons();
|
||||
RefreshAllUi();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RegisterInstance();
|
||||
BindButtons();
|
||||
settlementController.OnSettlementCompleted -= HandleSettlementCompleted;
|
||||
settlementController.OnSettlementCompleted += HandleSettlementCompleted;
|
||||
RefreshAllUi();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
settlementController.OnSettlementCompleted -= HandleSettlementCompleted;
|
||||
Instances.Remove(this);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
settlementController.OnSettlementCompleted -= HandleSettlementCompleted;
|
||||
Instances.Remove(this);
|
||||
}
|
||||
|
||||
public static bool IsEquipmentAssignedToSmeltPool(equipmentSO equipment)
|
||||
{
|
||||
return equipment != null && SmeltPoolLookup.Contains(equipment);
|
||||
}
|
||||
|
||||
public static bool IsEquipmentConsumedBySmelt(equipmentSO equipment)
|
||||
{
|
||||
return equipment != null && ConsumedSmeltEquipments.Contains(equipment);
|
||||
}
|
||||
|
||||
public static bool RemoveEquipmentFromSmeltPool(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SmeltPoolLookup.Remove(equipment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SmeltPoolEquipments.Remove(equipment);
|
||||
RefreshAllSmeltPools();
|
||||
RefreshAllEquipBags();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryHandleQuickTransfer(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null || IsEquipmentConsumedBySmelt(equipment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
equipSmelt activeSmelt = GetActivePoolInstance();
|
||||
if (activeSmelt == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsEquipmentAssignedToSmeltPool(equipment))
|
||||
{
|
||||
return RemoveEquipmentFromSmeltPool(equipment);
|
||||
}
|
||||
|
||||
activeSmelt.AcceptDraggedEquipment(equipment);
|
||||
return IsEquipmentAssignedToSmeltPool(equipment);
|
||||
}
|
||||
|
||||
public void SetDragPreviewVisible(bool visible)
|
||||
{
|
||||
if (dragObj == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsPoolOpenForTransfers())
|
||||
{
|
||||
dragObj.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldShow = visible || SmeltPoolEquipments.Count == 0;
|
||||
dragObj.SetActive(shouldShow);
|
||||
}
|
||||
|
||||
public bool IsPointerOverDropArea(Vector2 screenPoint, Camera eventCamera)
|
||||
{
|
||||
if (dragObj == null || !dragObj.activeInHierarchy || !IsPoolOpenForTransfers())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RectTransform[] rects = dragObj.GetComponentsInChildren<RectTransform>(true);
|
||||
if (rects == null || rects.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rects.Length; i++)
|
||||
{
|
||||
RectTransform rect = rects[i];
|
||||
if (rect == null || !rect.gameObject.activeInHierarchy)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RectTransformUtility.RectangleContainsScreenPoint(rect, screenPoint, eventCamera))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AcceptDraggedEquipment(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null || IsEquipmentConsumedBySmelt(equipment) || !IsPoolOpenForTransfers())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int capacity = GetSmeltEquipmentCapacity();
|
||||
if (capacity <= 0 || SmeltPoolEquipments.Count >= capacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SmeltPoolLookup.Add(equipment))
|
||||
{
|
||||
SmeltPoolEquipments.Add(equipment);
|
||||
RefreshAllUi();
|
||||
RefreshAllEquipBags();
|
||||
}
|
||||
}
|
||||
|
||||
private void BindButtons()
|
||||
{
|
||||
if (startSmeltButton != null)
|
||||
{
|
||||
startSmeltButton.onClick.RemoveListener(HandleStartSmeltClicked);
|
||||
startSmeltButton.onClick.AddListener(HandleStartSmeltClicked);
|
||||
}
|
||||
|
||||
if (quickFinishButton != null)
|
||||
{
|
||||
quickFinishButton.onClick.RemoveListener(HandleQuickFinishClicked);
|
||||
quickFinishButton.onClick.AddListener(HandleQuickFinishClicked);
|
||||
}
|
||||
|
||||
if (getReward != null)
|
||||
{
|
||||
getReward.onClick.RemoveListener(HandleGetRewardClicked);
|
||||
getReward.onClick.AddListener(HandleGetRewardClicked);
|
||||
}
|
||||
|
||||
if (selectAReward != null)
|
||||
{
|
||||
selectAReward.onValueChanged.RemoveListener(HandleRewardSelectionChanged);
|
||||
selectAReward.onValueChanged.AddListener(HandleRewardSelectionChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStartSmeltClicked()
|
||||
{
|
||||
if (smeltCompletedState)
|
||||
{
|
||||
ClaimCurrentBatchRewards();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSmeltingState || SmeltPoolEquipments.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isSmeltingState = true;
|
||||
smeltCompletedState = false;
|
||||
gamesCompletedForCurrentBatchState = 0;
|
||||
gamesRequiredForCurrentBatchState = Mathf.Max(1, Mathf.CeilToInt(SmeltPoolEquipments.Count / 20f));
|
||||
|
||||
int totalFragments = CalculateTotalFragmentsForCurrentPool();
|
||||
pendingDirectFragmentsState = Mathf.FloorToInt(totalFragments * 0.7f);
|
||||
pendingStoredFragmentsState = Mathf.Max(0, totalFragments - pendingDirectFragmentsState);
|
||||
|
||||
ConsumeCurrentPoolEquipments();
|
||||
RefreshAllUi();
|
||||
RefreshAllEquipBags();
|
||||
}
|
||||
|
||||
private void HandleQuickFinishClicked()
|
||||
{
|
||||
if (!isSmeltingState || smeltCompletedState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int cost = GetQuickFinishCost();
|
||||
if (!PlayerEconomyLedger.EnsureInstance().TrySpendCoins(cost))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gamesCompletedForCurrentBatchState = gamesRequiredForCurrentBatchState;
|
||||
smeltCompletedState = true;
|
||||
RefreshAllUi();
|
||||
}
|
||||
|
||||
private void HandleSettlementCompleted()
|
||||
{
|
||||
if (!isSmeltingState || smeltCompletedState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gamesCompletedForCurrentBatchState = Mathf.Min(gamesRequiredForCurrentBatchState, gamesCompletedForCurrentBatchState + 1);
|
||||
if (gamesCompletedForCurrentBatchState >= gamesRequiredForCurrentBatchState)
|
||||
{
|
||||
smeltCompletedState = true;
|
||||
}
|
||||
|
||||
RefreshAllUi();
|
||||
}
|
||||
|
||||
private void ClaimCurrentBatchRewards()
|
||||
{
|
||||
if (!smeltCompletedState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingDirectFragmentsState > 0)
|
||||
{
|
||||
PlayerEconomyLedger.EnsureInstance().AddMaterial(pendingDirectFragmentsState);
|
||||
}
|
||||
|
||||
storedSmeltEnergyState = Mathf.Clamp(storedSmeltEnergyState + pendingStoredFragmentsState, 0, GetSmeltStorageCapacity());
|
||||
|
||||
pendingDirectFragmentsState = 0;
|
||||
pendingStoredFragmentsState = 0;
|
||||
gamesRequiredForCurrentBatchState = 0;
|
||||
gamesCompletedForCurrentBatchState = 0;
|
||||
isSmeltingState = false;
|
||||
smeltCompletedState = false;
|
||||
|
||||
if (d_mf_Amount != null)
|
||||
{
|
||||
d_mf_Amount.text = "0";
|
||||
}
|
||||
|
||||
if (s_mf_Amount != null)
|
||||
{
|
||||
s_mf_Amount.text = "0";
|
||||
}
|
||||
|
||||
RefreshAllUi();
|
||||
RefreshAllEquipBags();
|
||||
}
|
||||
|
||||
private void HandleGetRewardClicked()
|
||||
{
|
||||
smeltStageRewardSO.SmeltStageRewardRequirement requirement = GetSelectedRewardRequirement();
|
||||
if (requirement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int requiredAmount = Mathf.Max(0, requirement.requiredAmount);
|
||||
if (requiredAmount > storedSmeltEnergyState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
equipmentSO generated = equipmentGenerator.GenerateFromSmeltReward(ssrso, requirement);
|
||||
if (generated == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
storedSmeltEnergyState = Mathf.Max(0, storedSmeltEnergyState - requiredAmount);
|
||||
RefreshAllUi();
|
||||
RefreshAllEquipBags();
|
||||
}
|
||||
|
||||
private void HandleRewardSelectionChanged(int _)
|
||||
{
|
||||
RefreshButtons();
|
||||
}
|
||||
|
||||
private void ConsumeCurrentPoolEquipments()
|
||||
{
|
||||
if (SmeltPoolEquipments.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SmeltPoolEquipments.Count; i++)
|
||||
{
|
||||
equipmentSO equipment = SmeltPoolEquipments[i];
|
||||
if (equipment == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ConsumedSmeltEquipments.Add(equipment);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
string assetPath = AssetDatabase.GetAssetPath(equipment);
|
||||
if (!string.IsNullOrWhiteSpace(assetPath) && assetPath.StartsWith("Assets/Resources/so/uEquip/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SmeltPoolEquipments.Clear();
|
||||
SmeltPoolLookup.Clear();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void RefreshAllUi()
|
||||
{
|
||||
ApplySmeltViewState();
|
||||
RebuildSmeltPool();
|
||||
RefreshRewardPreview();
|
||||
RefreshStoredEnergyDisplay();
|
||||
RefreshRewardDropdown();
|
||||
RefreshProgressDisplay();
|
||||
RefreshButtons();
|
||||
RefreshReasonWhy();
|
||||
}
|
||||
|
||||
private void ApplySmeltViewState()
|
||||
{
|
||||
if (smeltPool != null)
|
||||
{
|
||||
smeltPool.SetActive(!isSmeltingState);
|
||||
}
|
||||
|
||||
if (smeltProgress != null)
|
||||
{
|
||||
smeltProgress.SetActive(isSmeltingState);
|
||||
}
|
||||
|
||||
SetDragPreviewVisible(false);
|
||||
}
|
||||
|
||||
private bool IsPoolOpenForTransfers()
|
||||
{
|
||||
return gameObject.activeInHierarchy && smeltPool != null && smeltPool.activeInHierarchy && !isSmeltingState;
|
||||
}
|
||||
|
||||
private void RebuildSmeltPool()
|
||||
{
|
||||
ClearSmeltPoolItems();
|
||||
|
||||
if (smeltPoolItemPrefab == null || smeltPoolContent == null)
|
||||
{
|
||||
SetDragPreviewVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SmeltPoolEquipments.Count; i++)
|
||||
{
|
||||
equipmentSO equipment = SmeltPoolEquipments[i];
|
||||
if (equipment == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject instance = Instantiate(smeltPoolItemPrefab, smeltPoolContent);
|
||||
instance.name = string.IsNullOrWhiteSpace(equipment.GetCurrentTierDisplayName()) ? equipment.name : equipment.GetCurrentTierDisplayName();
|
||||
instance.SetActive(true);
|
||||
spawnedPoolItems.Add(instance);
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(equipment);
|
||||
}
|
||||
}
|
||||
|
||||
int placeholderToSpawn = Mathf.Max(0, GetSmeltEquipmentCapacity() - SmeltPoolEquipments.Count);
|
||||
for (int i = 0; i < placeholderToSpawn; i++)
|
||||
{
|
||||
GameObject instance = Instantiate(smeltPoolItemPrefab, smeltPoolContent);
|
||||
instance.name = $"SmeltPlaceholder_{i:00}";
|
||||
instance.SetActive(true);
|
||||
spawnedPoolItems.Add(instance);
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(null);
|
||||
if (item.itemButton != null)
|
||||
{
|
||||
item.itemButton.interactable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetDragPreviewVisible(false);
|
||||
}
|
||||
|
||||
private void RefreshRewardPreview()
|
||||
{
|
||||
bool useLockedBatchReward = isSmeltingState || smeltCompletedState;
|
||||
|
||||
int directReward;
|
||||
int savedReward;
|
||||
|
||||
if (useLockedBatchReward)
|
||||
{
|
||||
directReward = Mathf.Max(0, pendingDirectFragmentsState);
|
||||
savedReward = Mathf.Max(0, pendingStoredFragmentsState);
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalFragments = CalculateTotalFragmentsForCurrentPool();
|
||||
directReward = Mathf.FloorToInt(totalFragments * 0.7f);
|
||||
savedReward = Mathf.Max(0, totalFragments - directReward);
|
||||
}
|
||||
|
||||
if (d_mf_Amount != null)
|
||||
{
|
||||
d_mf_Amount.text = directReward.ToString();
|
||||
}
|
||||
|
||||
if (s_mf_Amount != null)
|
||||
{
|
||||
s_mf_Amount.text = savedReward.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshProgressDisplay()
|
||||
{
|
||||
if (qf_cost_text != null)
|
||||
{
|
||||
qf_cost_text.text = GetQuickFinishCost().ToString();
|
||||
}
|
||||
|
||||
if (stpSlider != null)
|
||||
{
|
||||
int required = Mathf.Max(1, gamesRequiredForCurrentBatchState);
|
||||
stpSlider.minValue = 0f;
|
||||
stpSlider.maxValue = required;
|
||||
stpSlider.value = Mathf.Clamp(gamesCompletedForCurrentBatchState, 0, required);
|
||||
|
||||
Text sliderText = stpSlider.GetComponentInChildren<Text>(true);
|
||||
if (sliderText != null)
|
||||
{
|
||||
sliderText.text = $"融合进度{Mathf.Clamp(gamesCompletedForCurrentBatchState, 0, required)}/{required}";
|
||||
}
|
||||
}
|
||||
|
||||
if (smeltStatusText != null)
|
||||
{
|
||||
if (!isSmeltingState)
|
||||
{
|
||||
smeltStatusText.text = string.Empty;
|
||||
}
|
||||
else if (smeltCompletedState)
|
||||
{
|
||||
smeltStatusText.text = "融合完毕,可以收获结果";
|
||||
}
|
||||
else
|
||||
{
|
||||
int remain = Mathf.Max(0, gamesRequiredForCurrentBatchState - gamesCompletedForCurrentBatchState);
|
||||
smeltStatusText.text = $"正在融合,还需{remain}场比赛";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshStoredEnergyDisplay()
|
||||
{
|
||||
int capacity = GetSmeltStorageCapacity();
|
||||
if (rewardGenProgress != null)
|
||||
{
|
||||
rewardGenProgress.text = $"{storedSmeltEnergyState}/{capacity}";
|
||||
}
|
||||
|
||||
if (rewardProgressImage != null)
|
||||
{
|
||||
rewardProgressImage.fillAmount = capacity <= 0 ? 0f : Mathf.Clamp01((float)storedSmeltEnergyState / capacity);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshRewardDropdown()
|
||||
{
|
||||
if (selectAReward == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
selectAReward.ClearOptions();
|
||||
if (selectAReward.captionText != null)
|
||||
{
|
||||
selectAReward.captionText.supportRichText = true;
|
||||
}
|
||||
|
||||
if (selectAReward.itemText != null)
|
||||
{
|
||||
selectAReward.itemText.supportRichText = true;
|
||||
}
|
||||
|
||||
var options = new List<Dropdown.OptionData>();
|
||||
if (ssrso != null && ssrso.rewardRequirements != null)
|
||||
{
|
||||
for (int i = 0; i < ssrso.rewardRequirements.Length; i++)
|
||||
{
|
||||
smeltStageRewardSO.SmeltStageRewardRequirement requirement = ssrso.rewardRequirements[i];
|
||||
string optionName = requirement != null ? requirement.equipRewardName : string.Empty;
|
||||
int requiredAmount = requirement != null ? Mathf.Max(0, requirement.requiredAmount) : 0;
|
||||
string color = string.IsNullOrWhiteSpace(optionName)
|
||||
? "#808080"
|
||||
: (requiredAmount > storedSmeltEnergyState ? "#FF0000" : "#FFFFFF");
|
||||
options.Add(new Dropdown.OptionData($"<color={color}>{(string.IsNullOrWhiteSpace(optionName) ? "未命名奖励" : optionName)}</color>"));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.Count == 0)
|
||||
{
|
||||
options.Add(new Dropdown.OptionData("<color=#808080>暂无奖励</color>"));
|
||||
}
|
||||
|
||||
selectAReward.AddOptions(options);
|
||||
selectAReward.value = 0;
|
||||
selectAReward.RefreshShownValue();
|
||||
}
|
||||
|
||||
private void RefreshButtons()
|
||||
{
|
||||
if (startSmeltButton != null)
|
||||
{
|
||||
startSmeltButton.interactable = smeltCompletedState || (!isSmeltingState && SmeltPoolEquipments.Count > 0);
|
||||
Text startButtonText = startSmeltButton.GetComponentInChildren<Text>(true);
|
||||
if (startButtonText != null)
|
||||
{
|
||||
startButtonText.text = smeltCompletedState ? "领取碎片" : "开始融合";
|
||||
}
|
||||
}
|
||||
|
||||
if (quickFinishButton != null)
|
||||
{
|
||||
quickFinishButton.interactable = isSmeltingState && !smeltCompletedState && PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(GetQuickFinishCost());
|
||||
}
|
||||
|
||||
if (getReward != null)
|
||||
{
|
||||
smeltStageRewardSO.SmeltStageRewardRequirement requirement = GetSelectedRewardRequirement();
|
||||
getReward.interactable = requirement != null && Mathf.Max(0, requirement.requiredAmount) <= storedSmeltEnergyState;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshReasonWhy()
|
||||
{
|
||||
if (reasonWhy == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (smeltCompletedState)
|
||||
{
|
||||
reasonWhy.text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSmeltingState)
|
||||
{
|
||||
reasonWhy.text = "正在融合中";
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSmeltEquipmentCapacity() <= 0)
|
||||
{
|
||||
reasonWhy.text = "熔炉容量为0";
|
||||
return;
|
||||
}
|
||||
|
||||
if (SmeltPoolEquipments.Count <= 0)
|
||||
{
|
||||
reasonWhy.text = "需要投入记忆";
|
||||
return;
|
||||
}
|
||||
|
||||
reasonWhy.text = string.Empty;
|
||||
}
|
||||
|
||||
private int CalculateTotalFragmentsForCurrentPool()
|
||||
{
|
||||
int totalFragments = 0;
|
||||
for (int i = 0; i < SmeltPoolEquipments.Count; i++)
|
||||
{
|
||||
equipmentSO equipment = SmeltPoolEquipments[i];
|
||||
if (equipment == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
totalFragments += GetFragmentReward(equipment);
|
||||
}
|
||||
|
||||
return totalFragments;
|
||||
}
|
||||
|
||||
private int GetFragmentReward(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int skillCount = 0;
|
||||
if (equipment.sa_skillID > 0)
|
||||
{
|
||||
skillCount++;
|
||||
}
|
||||
|
||||
if (equipment.ia_skillID > 0)
|
||||
{
|
||||
skillCount++;
|
||||
}
|
||||
|
||||
int simpleReward = ssrso != null ? ssrso.simpleRewardAmount : 40;
|
||||
int oneSkillReward = ssrso != null ? ssrso._1skillRewardAmount : 100;
|
||||
int twoSkillReward = ssrso != null ? ssrso._2skillRewardAmount : 300;
|
||||
|
||||
switch (skillCount)
|
||||
{
|
||||
case 0: return simpleReward;
|
||||
case 1: return oneSkillReward;
|
||||
default: return twoSkillReward;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetSmeltEquipmentCapacity()
|
||||
{
|
||||
if (ssrso == null)
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
|
||||
return Mathf.Clamp(ssrso.smeltEquipmentCapacity, 0, 100);
|
||||
}
|
||||
|
||||
private int GetSmeltStorageCapacity()
|
||||
{
|
||||
if (ssrso == null)
|
||||
{
|
||||
return 5000;
|
||||
}
|
||||
|
||||
return Mathf.Clamp(ssrso.smeltStorageCapacity, 0, 5000);
|
||||
}
|
||||
|
||||
private int GetQuickFinishCost()
|
||||
{
|
||||
return ssrso != null ? Mathf.Max(0, ssrso.quickFinishCost) : 0;
|
||||
}
|
||||
|
||||
private smeltStageRewardSO.SmeltStageRewardRequirement GetSelectedRewardRequirement()
|
||||
{
|
||||
if (ssrso == null || ssrso.rewardRequirements == null || ssrso.rewardRequirements.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int selectedIndex = selectAReward != null ? Mathf.Clamp(selectAReward.value, 0, ssrso.rewardRequirements.Length - 1) : 0;
|
||||
return ssrso.rewardRequirements[selectedIndex];
|
||||
}
|
||||
|
||||
private static equipSmelt GetActivePoolInstance()
|
||||
{
|
||||
for (int i = 0; i < Instances.Count; i++)
|
||||
{
|
||||
equipSmelt instance = Instances[i];
|
||||
if (instance != null && instance.IsPoolOpenForTransfers())
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ClearSmeltPoolItems()
|
||||
{
|
||||
for (int i = smeltPoolContent != null ? smeltPoolContent.childCount - 1 : -1; i >= 0; i--)
|
||||
{
|
||||
Transform child = smeltPoolContent.GetChild(i);
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
DestroyImmediate(child.gameObject);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
spawnedPoolItems.Clear();
|
||||
}
|
||||
|
||||
private void RegisterInstance()
|
||||
{
|
||||
if (!Instances.Contains(this))
|
||||
{
|
||||
Instances.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RefreshAllSmeltPools()
|
||||
{
|
||||
for (int i = 0; i < Instances.Count; i++)
|
||||
{
|
||||
if (Instances[i] != null)
|
||||
{
|
||||
Instances[i].RefreshAllUi();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RefreshAllEquipBags()
|
||||
{
|
||||
equipBag[] bags = FindObjectsOfType<equipBag>(true);
|
||||
if (bags == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bags.Length; i++)
|
||||
{
|
||||
if (bags[i] != null)
|
||||
{
|
||||
bags[i].Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd1800d187f8a2c4b812348553e003ef
|
||||
@@ -0,0 +1,52 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "SmeltStageRewardSO", menuName = "Equipment/Equipment Smelt Stage Reward SO")]
|
||||
public class smeltStageRewardSO : ScriptableObject
|
||||
{
|
||||
public enum equipType
|
||||
{
|
||||
randomType,
|
||||
selfChosenType,
|
||||
}
|
||||
|
||||
public enum attributeQuality
|
||||
{
|
||||
randomQuality,
|
||||
highQuality,
|
||||
}
|
||||
|
||||
public enum skillOwned
|
||||
{
|
||||
followRandom,
|
||||
mustHave,
|
||||
selfChosen
|
||||
}
|
||||
|
||||
[Header("fragment rewards")]
|
||||
public int simpleRewardAmount = 40;
|
||||
public int _1skillRewardAmount = 100;
|
||||
public int _2skillRewardAmount = 300;
|
||||
public int quickFinishCost = 200;
|
||||
|
||||
[Header("reward generation")]
|
||||
public equipmentRandomConfigSO rewardRandomConfig;
|
||||
public equipmentSO rewardTemplate;
|
||||
|
||||
[Header("smelter limits")]
|
||||
[Range(0, 100)] public int smeltEquipmentCapacity = 60;
|
||||
[Range(0, 5000)] public int smeltStorageCapacity = 5000;
|
||||
|
||||
[System.Serializable]
|
||||
public class SmeltStageRewardRequirement
|
||||
{
|
||||
public equipType equipmentType;
|
||||
public attributeQuality qualityType;
|
||||
public skillOwned skillRequirement;
|
||||
public equipmentSO.EquipmentSkillType chosenSkillType;
|
||||
public string equipRewardName;
|
||||
public int requiredAmount;
|
||||
}
|
||||
|
||||
[Header("stage rewards")]
|
||||
public SmeltStageRewardRequirement[] rewardRequirements;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51eaa69f0e6f47a48a3391b66f902d8b
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99e7eb1c16843064db36f0877563f2a1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 21557314f50e3bf4db9d860c5adfc61c, type: 3}
|
||||
m_Name: EquipmentUpdateSO
|
||||
m_EditorClassIdentifier:
|
||||
upgradeMaterial: {fileID: 11400000, guid: 4b7d886fc44e4cbe9db602da8c2f9c11, type: 2}
|
||||
breakthroughMaterial: {fileID: 11400000, guid: 6b403344b9414dbba95b7311c3ff57fa, type: 2}
|
||||
upgradeMaterialBase: 3
|
||||
upgradeMaterialGrowth: 3
|
||||
upgradeCoinsBase: 3
|
||||
upgradeCoinsGrowth: 3
|
||||
upgradeMemoryFragmentBase: 3
|
||||
upgradeMemoryFragmentGrowth: 3
|
||||
breakthroughStageCosts:
|
||||
- materialRequired: 30
|
||||
coinRequired: 1000
|
||||
- materialRequired: 75
|
||||
coinRequired: 2500
|
||||
- materialRequired: 125
|
||||
coinRequired: 4000
|
||||
- materialRequired: 200
|
||||
coinRequired: 10000
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8efade7387483747a7baf2668a9674b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,113 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "EquipmentUpdateSO", menuName = "Equipment/EquipmentUpdateSO")]
|
||||
public class eUpdate_mtrSO : ScriptableObject
|
||||
{
|
||||
[System.Serializable]
|
||||
public class BreakthroughStageCost
|
||||
{
|
||||
[Tooltip("breakthroughMaterial required count")]
|
||||
public int materialRequired;
|
||||
[Tooltip("coin required count")]
|
||||
public int coinRequired;
|
||||
}
|
||||
|
||||
[Header("Material Definitions")]
|
||||
[Tooltip("Fixed equipment upgrade consumable definition: 78101")]
|
||||
public equipmentConsumableSO upgradeMaterial;
|
||||
[Tooltip("Fixed equipment breakthrough consumable definition: 78111")]
|
||||
public equipmentConsumableSO breakthroughMaterial;
|
||||
|
||||
[Header("Upgrade Cost")]
|
||||
[Tooltip("Upgrade material required count = base + level * growth")]
|
||||
public int upgradeMaterialBase = 1;
|
||||
public int upgradeMaterialGrowth;
|
||||
[Tooltip("Upgrade coin required count = base + level * growth")]
|
||||
public int upgradeCoinsBase;
|
||||
public int upgradeCoinsGrowth;
|
||||
[Tooltip("Upgrade memory fragment required count = base + level * growth")]
|
||||
public int upgradeMemoryFragmentBase;
|
||||
public int upgradeMemoryFragmentGrowth;
|
||||
|
||||
[Header("Breakthrough Cost")]
|
||||
[Tooltip("Index 0-3 -> level 4/9/14/19")]
|
||||
public BreakthroughStageCost[] breakthroughStageCosts = new BreakthroughStageCost[4];
|
||||
|
||||
public int GetUpgradeMaterialRequired(int level)
|
||||
{
|
||||
return Mathf.Max(0, upgradeMaterialBase + Mathf.Max(0, level) * upgradeMaterialGrowth);
|
||||
}
|
||||
|
||||
public int GetBreakthroughMaterialRequired(int level)
|
||||
{
|
||||
int stageIndex = GetBreakthroughStageIndex(level);
|
||||
if (stageIndex < 0 || breakthroughStageCosts == null || stageIndex >= breakthroughStageCosts.Length || breakthroughStageCosts[stageIndex] == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Max(0, breakthroughStageCosts[stageIndex].materialRequired);
|
||||
}
|
||||
|
||||
public int GetUpgradeCoinsRequired(int level)
|
||||
{
|
||||
return Mathf.Max(0, upgradeCoinsBase + Mathf.Max(0, level) * upgradeCoinsGrowth);
|
||||
}
|
||||
|
||||
public int GetUpgradeMemoryFragmentRequired(int level)
|
||||
{
|
||||
return Mathf.Max(0, upgradeMemoryFragmentBase + Mathf.Max(0, level) * upgradeMemoryFragmentGrowth);
|
||||
}
|
||||
|
||||
public int GetBreakthroughCoinsRequired(int level)
|
||||
{
|
||||
int stageIndex = GetBreakthroughStageIndex(level);
|
||||
if (stageIndex < 0 || breakthroughStageCosts == null || stageIndex >= breakthroughStageCosts.Length || breakthroughStageCosts[stageIndex] == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Max(0, breakthroughStageCosts[stageIndex].coinRequired);
|
||||
}
|
||||
|
||||
public int GetBreakthroughStageIndex(int level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case 4:
|
||||
return 0;
|
||||
case 9:
|
||||
return 1;
|
||||
case 14:
|
||||
return 2;
|
||||
case 19:
|
||||
return 3;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (breakthroughStageCosts == null || breakthroughStageCosts.Length != 4)
|
||||
{
|
||||
var resized = new BreakthroughStageCost[4];
|
||||
if (breakthroughStageCosts != null)
|
||||
{
|
||||
for (int i = 0; i < Mathf.Min(breakthroughStageCosts.Length, resized.Length); i++)
|
||||
{
|
||||
resized[i] = breakthroughStageCosts[i];
|
||||
}
|
||||
}
|
||||
|
||||
breakthroughStageCosts = resized;
|
||||
}
|
||||
|
||||
for (int i = 0; i < breakthroughStageCosts.Length; i++)
|
||||
{
|
||||
breakthroughStageCosts[i] ??= new BreakthroughStageCost();
|
||||
breakthroughStageCosts[i].materialRequired = Mathf.Max(0, breakthroughStageCosts[i].materialRequired);
|
||||
breakthroughStageCosts[i].coinRequired = Mathf.Max(0, breakthroughStageCosts[i].coinRequired);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21557314f50e3bf4db9d860c5adfc61c
|
||||
@@ -0,0 +1,673 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class equipUpdate : MonoBehaviour
|
||||
{
|
||||
[Header("so")]
|
||||
public Player_SO playerSO;
|
||||
public equipmentSO eqp_p_SO;
|
||||
public eUpdate_mtrSO need_mtrSO;
|
||||
|
||||
[Header("state objects")]
|
||||
public GameObject beforeObj;
|
||||
public GameObject toObj;
|
||||
public GameObject nextObj;
|
||||
|
||||
[Header("dragging")]
|
||||
public GameObject dragPrev;
|
||||
|
||||
[Header("transforms")]
|
||||
public Transform prevLevelEquip;
|
||||
public Transform nextLevelEquip;
|
||||
public GameObject eip;
|
||||
|
||||
[Header("texts")]
|
||||
public Text prevLevelText;
|
||||
public Text nextLevelText;
|
||||
public Text reasonWhy;
|
||||
|
||||
[Header("materials")]
|
||||
public GameObject mtrPrefab;
|
||||
public Transform mtrParent;
|
||||
public Text mtrInfo;
|
||||
|
||||
[Header("sprites")]
|
||||
public Sprite MemoryFragmentSprite;
|
||||
public Sprite coinSprite;
|
||||
|
||||
[Header("buttons")]
|
||||
public Button yesUpdateButton;
|
||||
|
||||
private GameObject spawnedPrevLevelInstance;
|
||||
private GameObject spawnedNextLevelInstance;
|
||||
private equipmentSO nextLevelPreviewSO;
|
||||
private readonly List<GameObject> spawnedMaterialItems = new List<GameObject>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
InitializeBindings();
|
||||
SetDragPreviewVisible(false);
|
||||
ResetInitialSelectionState();
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
InitializeBindings();
|
||||
SetDragPreviewVisible(false);
|
||||
ResetInitialSelectionState();
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (yesUpdateButton != null)
|
||||
{
|
||||
yesUpdateButton.onClick.RemoveListener(HandleYesUpdateClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeBindings()
|
||||
{
|
||||
if (playerSO != null)
|
||||
{
|
||||
PlayerEconomyLedger.EnsureInstance().AttachPlayerData(playerSO);
|
||||
}
|
||||
|
||||
if (yesUpdateButton != null)
|
||||
{
|
||||
yesUpdateButton.onClick.RemoveListener(HandleYesUpdateClicked);
|
||||
yesUpdateButton.onClick.AddListener(HandleYesUpdateClicked);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDragPreviewVisible(bool visible)
|
||||
{
|
||||
if (dragPrev == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gameObject.activeInHierarchy)
|
||||
{
|
||||
dragPrev.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dragPrev != null)
|
||||
{
|
||||
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;
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void RefreshAll()
|
||||
{
|
||||
RefreshPrevLevelPreview();
|
||||
RefreshNextLevelPreview();
|
||||
RefreshSelectionState();
|
||||
RefreshPrevLevelText();
|
||||
RefreshNextLevelText();
|
||||
RefreshMaterialRequirements();
|
||||
RefreshActionState();
|
||||
}
|
||||
|
||||
public void RefreshPrevLevelPreview()
|
||||
{
|
||||
DestroyPrevLevelPreview();
|
||||
|
||||
if (eqp_p_SO == null || eip == null || prevLevelEquip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject instance = Instantiate(eip, prevLevelEquip);
|
||||
instance.name = $"{eqp_p_SO.name}_PrevLevel";
|
||||
instance.SetActive(true);
|
||||
spawnedPrevLevelInstance = instance;
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(eqp_p_SO);
|
||||
item.SetInteractionOptions(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshNextLevelPreview()
|
||||
{
|
||||
DestroyNextLevelPreview();
|
||||
|
||||
if (!CanShowNextPreview())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nextLevelPreviewSO = Instantiate(eqp_p_SO);
|
||||
nextLevelPreviewSO.level = Mathf.Clamp(eqp_p_SO.level + 1, 0, 20);
|
||||
|
||||
GameObject instance = Instantiate(eip, nextLevelEquip);
|
||||
instance.name = $"{eqp_p_SO.name}_NextLevel";
|
||||
instance.SetActive(true);
|
||||
spawnedNextLevelInstance = instance;
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(nextLevelPreviewSO);
|
||||
item.SetInteractionOptions(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanShowNextPreview()
|
||||
{
|
||||
if (eqp_p_SO == null || eip == null || nextLevelEquip == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int level = eqp_p_SO.level;
|
||||
if (level < 0 || level >= 20)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !RequiresTour(level);
|
||||
}
|
||||
|
||||
private void RefreshSelectionState()
|
||||
{
|
||||
bool hasSelection = eqp_p_SO != null && spawnedPrevLevelInstance != null;
|
||||
bool requiresTour = hasSelection && RequiresTour(eqp_p_SO.level);
|
||||
bool isMaxLevel = hasSelection && eqp_p_SO.level >= 20;
|
||||
bool isInvalidLevel = hasSelection && !IsLegalLevel(eqp_p_SO.level);
|
||||
|
||||
if (beforeObj != null)
|
||||
{
|
||||
beforeObj.SetActive(true);
|
||||
}
|
||||
|
||||
bool showProgressObjects = hasSelection && !requiresTour && !isMaxLevel && !isInvalidLevel;
|
||||
|
||||
if (toObj != null)
|
||||
{
|
||||
toObj.SetActive(showProgressObjects);
|
||||
}
|
||||
|
||||
if (nextObj != null)
|
||||
{
|
||||
nextObj.SetActive(showProgressObjects);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshPrevLevelText()
|
||||
{
|
||||
if (prevLevelText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eqp_p_SO == null)
|
||||
{
|
||||
prevLevelText.text = "选择一个记忆";
|
||||
prevLevelText.color = Color.black;
|
||||
return;
|
||||
}
|
||||
|
||||
prevLevelText.text = $"{Mathf.Max(0, eqp_p_SO.level)}追忆等级";
|
||||
prevLevelText.color = ResolveEquipmentColor(GetQualityColorIndex(eqp_p_SO.level));
|
||||
}
|
||||
|
||||
private void RefreshNextLevelText()
|
||||
{
|
||||
if (nextLevelText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanShowNextPreview() || nextLevelPreviewSO == null)
|
||||
{
|
||||
nextLevelText.text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
nextLevelText.text = $"{Mathf.Max(0, nextLevelPreviewSO.level)}追忆等级";
|
||||
nextLevelText.color = ResolveEquipmentColor(GetQualityColorIndex(nextLevelPreviewSO.level));
|
||||
}
|
||||
|
||||
private void RefreshMaterialRequirements()
|
||||
{
|
||||
ClearSpawnedMaterialItems();
|
||||
|
||||
if (mtrInfo != null)
|
||||
{
|
||||
mtrInfo.text = "需要指定记忆";
|
||||
}
|
||||
|
||||
if (eqp_p_SO == null || need_mtrSO == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int level = eqp_p_SO.level;
|
||||
if (!IsLegalLevel(level))
|
||||
{
|
||||
if (mtrInfo != null)
|
||||
{
|
||||
mtrInfo.text = "装备不合法";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (level == 20)
|
||||
{
|
||||
if (mtrInfo != null)
|
||||
{
|
||||
mtrInfo.text = "<color=#FF69B4>梦醒装备已满级</color>";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (RequiresTour(level))
|
||||
{
|
||||
if (mtrInfo != null)
|
||||
{
|
||||
mtrInfo.text = "需要巡演";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mtrInfo != null)
|
||||
{
|
||||
mtrInfo.text = string.Empty;
|
||||
}
|
||||
|
||||
SpawnUpgradeMaterialItems(level);
|
||||
}
|
||||
|
||||
private void SpawnUpgradeMaterialItems(int level)
|
||||
{
|
||||
if (mtrPrefab == null || mtrParent == null || need_mtrSO == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int upgradeMaterialRequired = need_mtrSO.GetUpgradeMaterialRequired(level);
|
||||
int upgradeCoinsRequired = need_mtrSO.GetUpgradeCoinsRequired(level);
|
||||
int upgradeMemoryRequired = need_mtrSO.GetUpgradeMemoryFragmentRequired(level);
|
||||
|
||||
if (upgradeMaterialRequired > 0 && need_mtrSO.upgradeMaterial != null)
|
||||
{
|
||||
SpawnMaterialItem(
|
||||
need_mtrSO.upgradeMaterial.consumableSprite,
|
||||
need_mtrSO.upgradeMaterial.consumableName,
|
||||
upgradeMaterialRequired.ToString());
|
||||
}
|
||||
|
||||
if (upgradeCoinsRequired > 0)
|
||||
{
|
||||
SpawnMaterialItem(
|
||||
coinSprite,
|
||||
"Coins",
|
||||
upgradeCoinsRequired.ToString());
|
||||
}
|
||||
|
||||
if (upgradeMemoryRequired > 0)
|
||||
{
|
||||
SpawnMaterialItem(
|
||||
MemoryFragmentSprite,
|
||||
"记忆碎片",
|
||||
upgradeMemoryRequired.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnMaterialItem(Sprite sprite, string displayName, string amountText)
|
||||
{
|
||||
GameObject instance = Instantiate(mtrPrefab, mtrParent);
|
||||
instance.SetActive(true);
|
||||
spawnedMaterialItems.Add(instance);
|
||||
|
||||
materialPrefab item = instance.GetComponent<materialPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(sprite, displayName, amountText, true, false, null);
|
||||
item.SetSelected(true);
|
||||
if (item.materialButton != null)
|
||||
{
|
||||
item.materialButton.interactable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshActionState()
|
||||
{
|
||||
string failureReason = GetUpgradeFailureReason();
|
||||
|
||||
if (reasonWhy != null)
|
||||
{
|
||||
reasonWhy.text = string.IsNullOrEmpty(failureReason) ? string.Empty : failureReason;
|
||||
}
|
||||
|
||||
if (yesUpdateButton == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
yesUpdateButton.interactable = string.IsNullOrEmpty(failureReason);
|
||||
}
|
||||
|
||||
private bool CanUpgradeCurrent()
|
||||
{
|
||||
return string.IsNullOrEmpty(GetUpgradeFailureReason());
|
||||
}
|
||||
|
||||
private string GetUpgradeFailureReason()
|
||||
{
|
||||
if (eqp_p_SO == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (need_mtrSO == null)
|
||||
{
|
||||
return "未配置升级规则";
|
||||
}
|
||||
|
||||
int level = eqp_p_SO.level;
|
||||
if (!IsLegalLevel(level))
|
||||
{
|
||||
return "装备不合法";
|
||||
}
|
||||
|
||||
if (level >= 20)
|
||||
{
|
||||
return "梦醒装备已满级";
|
||||
}
|
||||
|
||||
if (RequiresTour(level))
|
||||
{
|
||||
return "当前等级需要巡演";
|
||||
}
|
||||
|
||||
int upgradeMaterialRequired = need_mtrSO.GetUpgradeMaterialRequired(level);
|
||||
int upgradeCoinsRequired = need_mtrSO.GetUpgradeCoinsRequired(level);
|
||||
int upgradeMemoryRequired = need_mtrSO.GetUpgradeMemoryFragmentRequired(level);
|
||||
|
||||
if (upgradeMaterialRequired > 0)
|
||||
{
|
||||
if (need_mtrSO.upgradeMaterial == null)
|
||||
{
|
||||
return "未配置升级材料";
|
||||
}
|
||||
|
||||
int ownedConsumable = EquipmentConsumableLedger.EnsureInstance().GetCount(need_mtrSO.upgradeMaterial.consumableKind);
|
||||
if (ownedConsumable < upgradeMaterialRequired)
|
||||
{
|
||||
return "升级材料不足";
|
||||
}
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(upgradeCoinsRequired))
|
||||
{
|
||||
return "硬币不足";
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughMaterial(upgradeMemoryRequired))
|
||||
{
|
||||
return "记忆碎片不足";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private void HandleYesUpdateClicked()
|
||||
{
|
||||
if (!CanUpgradeCurrent())
|
||||
{
|
||||
RefreshActionState();
|
||||
return;
|
||||
}
|
||||
|
||||
int currentLevel = eqp_p_SO.level;
|
||||
int upgradeMaterialRequired = need_mtrSO.GetUpgradeMaterialRequired(currentLevel);
|
||||
int upgradeCoinsRequired = need_mtrSO.GetUpgradeCoinsRequired(currentLevel);
|
||||
int upgradeMemoryRequired = need_mtrSO.GetUpgradeMemoryFragmentRequired(currentLevel);
|
||||
|
||||
if (upgradeMaterialRequired > 0)
|
||||
{
|
||||
if (need_mtrSO.upgradeMaterial == null || !EquipmentConsumableLedger.EnsureInstance().TryConsume(need_mtrSO.upgradeMaterial.consumableKind, upgradeMaterialRequired))
|
||||
{
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (upgradeCoinsRequired > 0 && !PlayerEconomyLedger.EnsureInstance().TrySpendCoins(upgradeCoinsRequired))
|
||||
{
|
||||
if (upgradeMaterialRequired > 0 && need_mtrSO.upgradeMaterial != null)
|
||||
{
|
||||
EquipmentConsumableLedger.EnsureInstance().Add(need_mtrSO.upgradeMaterial.consumableKind, upgradeMaterialRequired);
|
||||
}
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (upgradeMemoryRequired > 0 && !PlayerEconomyLedger.EnsureInstance().TrySpendMaterial(upgradeMemoryRequired))
|
||||
{
|
||||
if (upgradeCoinsRequired > 0)
|
||||
{
|
||||
PlayerEconomyLedger.EnsureInstance().AddCoins(upgradeCoinsRequired);
|
||||
}
|
||||
if (upgradeMaterialRequired > 0 && need_mtrSO.upgradeMaterial != null)
|
||||
{
|
||||
EquipmentConsumableLedger.EnsureInstance().Add(need_mtrSO.upgradeMaterial.consumableKind, upgradeMaterialRequired);
|
||||
}
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
|
||||
eqp_p_SO.level = Mathf.Clamp(eqp_p_SO.level + 1, 0, 20);
|
||||
PersistEquipmentLevel(eqp_p_SO);
|
||||
RefreshAllEquipBags();
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private static void PersistEquipmentLevel(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(equipment);
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void RefreshAllEquipBags()
|
||||
{
|
||||
equipBag[] bags = FindObjectsOfType<equipBag>(true);
|
||||
for (int i = 0; i < bags.Length; i++)
|
||||
{
|
||||
if (bags[i] != null)
|
||||
{
|
||||
bags[i].Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Color ResolveEquipmentColor(int colorIndex)
|
||||
{
|
||||
if (eip == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
equipItemPrefab itemPrefab = eip.GetComponent<equipItemPrefab>();
|
||||
if (itemPrefab == null || itemPrefab.itemBtmColors == null || itemPrefab.itemBtmColors.Length == 0)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
int safeIndex = Mathf.Clamp(colorIndex, 0, itemPrefab.itemBtmColors.Length - 1);
|
||||
return itemPrefab.itemBtmColors[safeIndex];
|
||||
}
|
||||
|
||||
private static int GetQualityColorIndex(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 bool IsLegalLevel(int level)
|
||||
{
|
||||
return level >= 0 && level <= 20;
|
||||
}
|
||||
|
||||
private static bool RequiresTour(int level)
|
||||
{
|
||||
return level == 4 || level == 9 || level == 14 || level == 19;
|
||||
}
|
||||
|
||||
private void ResetInitialSelectionState()
|
||||
{
|
||||
DestroyPrevLevelPreview();
|
||||
DestroyNextLevelPreview();
|
||||
ClearSpawnedMaterialItems();
|
||||
eqp_p_SO = null;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Object.DestroyImmediate(child.gameObject);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spawnedMaterialItems.Clear();
|
||||
}
|
||||
|
||||
private void DestroyPrevLevelPreview()
|
||||
{
|
||||
if (spawnedPrevLevelInstance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(spawnedPrevLevelInstance);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(spawnedPrevLevelInstance);
|
||||
}
|
||||
|
||||
spawnedPrevLevelInstance = null;
|
||||
}
|
||||
|
||||
private void DestroyNextLevelPreview()
|
||||
{
|
||||
if (spawnedNextLevelInstance != null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(spawnedNextLevelInstance);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(spawnedNextLevelInstance);
|
||||
}
|
||||
|
||||
spawnedNextLevelInstance = null;
|
||||
}
|
||||
|
||||
if (nextLevelPreviewSO != null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(nextLevelPreviewSO);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(nextLevelPreviewSO);
|
||||
}
|
||||
|
||||
nextLevelPreviewSO = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0233fcfb8bdea5045a2cfdcddad7dd7f
|
||||
@@ -0,0 +1,840 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class equipIllusion : MonoBehaviour
|
||||
{
|
||||
[Header("so")]
|
||||
public equipmentSO eqp_p_SO;
|
||||
public Player_SO playerSO;
|
||||
public eUpdate_mtrSO need_mtrSO;
|
||||
public equipmentRandomConfigSO randomConfig;
|
||||
|
||||
[Header("levelList")]
|
||||
public string[] illusionLevelName;
|
||||
|
||||
[Header("statusObj")]
|
||||
public GameObject beforeObj;
|
||||
public GameObject toObj;
|
||||
public GameObject nextObj;
|
||||
|
||||
[Header("dragging")]
|
||||
public GameObject dragPrev;
|
||||
|
||||
[Header("transforms")]
|
||||
public Transform prevIllusionEquip;
|
||||
public Transform nextIllusionEquip;
|
||||
public GameObject eip;
|
||||
|
||||
[Header("texts")]
|
||||
public Text prevLevelText;
|
||||
public Text nextLevelText;
|
||||
public Text reasonWhy;
|
||||
|
||||
[Header("materials")]
|
||||
public GameObject mtrPrefab;
|
||||
public Transform merParent;
|
||||
public Text mtrInfo;
|
||||
|
||||
[Header("sprites")]
|
||||
public Sprite memoryFragmentSprite;
|
||||
public Sprite coinSprite;
|
||||
|
||||
[Header("buttons")]
|
||||
public Button yesIllusionButton;
|
||||
|
||||
private GameObject spawnedPrevLevelInstance;
|
||||
private GameObject spawnedNextLevelInstance;
|
||||
private equipmentSO nextLevelPreviewSO;
|
||||
private readonly List<GameObject> spawnedMaterialItems = new List<GameObject>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
InitializeBindings();
|
||||
SetDragPreviewVisible(false);
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
InitializeBindings();
|
||||
SetDragPreviewVisible(false);
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (yesIllusionButton != null)
|
||||
{
|
||||
yesIllusionButton.onClick.RemoveListener(HandleYesIllusionClicked);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeBindings()
|
||||
{
|
||||
if (playerSO != null)
|
||||
{
|
||||
PlayerEconomyLedger.EnsureInstance().AttachPlayerData(playerSO);
|
||||
}
|
||||
|
||||
if (randomConfig != null)
|
||||
{
|
||||
randomConfig.NormalizeRuntimeData();
|
||||
}
|
||||
|
||||
if (yesIllusionButton != null)
|
||||
{
|
||||
yesIllusionButton.onClick.RemoveListener(HandleYesIllusionClicked);
|
||||
yesIllusionButton.onClick.AddListener(HandleYesIllusionClicked);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void RefreshAll()
|
||||
{
|
||||
RefreshPrevLevelPreview();
|
||||
RefreshNextLevelPreview();
|
||||
RefreshSelectionState();
|
||||
RefreshPrevLevelText();
|
||||
RefreshNextLevelText();
|
||||
RefreshMaterialRequirements();
|
||||
RefreshReasonWhy();
|
||||
RefreshActionState();
|
||||
}
|
||||
|
||||
private void RefreshPrevLevelPreview()
|
||||
{
|
||||
DestroyPrevLevelPreview();
|
||||
|
||||
if (eqp_p_SO == null || eip == null || prevIllusionEquip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject instance = Instantiate(eip, prevIllusionEquip);
|
||||
instance.name = $"{eqp_p_SO.name}_PrevTour";
|
||||
instance.SetActive(true);
|
||||
spawnedPrevLevelInstance = instance;
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(eqp_p_SO);
|
||||
item.SetInteractionOptions(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshNextLevelPreview()
|
||||
{
|
||||
DestroyNextLevelPreview();
|
||||
nextLevelPreviewSO = null;
|
||||
|
||||
if (!CanShowNextPreview())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nextLevelPreviewSO = Instantiate(eqp_p_SO);
|
||||
nextLevelPreviewSO.level = Mathf.Clamp(eqp_p_SO.level + 1, 0, 20);
|
||||
nextLevelPreviewSO.name = $"{eqp_p_SO.name}(TourPreview)";
|
||||
|
||||
GameObject instance = Instantiate(eip, nextIllusionEquip);
|
||||
instance.name = $"{eqp_p_SO.name}_NextTour";
|
||||
instance.SetActive(true);
|
||||
spawnedNextLevelInstance = instance;
|
||||
|
||||
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(nextLevelPreviewSO);
|
||||
item.SetInteractionOptions(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanShowNextPreview()
|
||||
{
|
||||
return eqp_p_SO != null && eip != null && nextIllusionEquip != null && IsTourEligibleLevel(eqp_p_SO.level);
|
||||
}
|
||||
|
||||
private void RefreshSelectionState()
|
||||
{
|
||||
if (beforeObj != null)
|
||||
{
|
||||
beforeObj.SetActive(true);
|
||||
}
|
||||
|
||||
bool showRightSide = eqp_p_SO != null && IsTourEligibleLevel(eqp_p_SO.level);
|
||||
if (toObj != null)
|
||||
{
|
||||
toObj.SetActive(showRightSide);
|
||||
}
|
||||
|
||||
if (nextObj != null)
|
||||
{
|
||||
nextObj.SetActive(showRightSide);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshPrevLevelText()
|
||||
{
|
||||
if (prevLevelText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eqp_p_SO == null)
|
||||
{
|
||||
prevLevelText.text = "选择一个记忆";
|
||||
prevLevelText.color = Color.black;
|
||||
return;
|
||||
}
|
||||
|
||||
prevLevelText.text = ResolveTourStageName(eqp_p_SO.level);
|
||||
prevLevelText.color = ResolveEquipmentColor(GetQualityColorIndex(eqp_p_SO.level));
|
||||
}
|
||||
|
||||
private void RefreshNextLevelText()
|
||||
{
|
||||
if (nextLevelText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanShowNextPreview() || nextLevelPreviewSO == null)
|
||||
{
|
||||
nextLevelText.text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
nextLevelText.text = ResolveTourStageName(nextLevelPreviewSO.level);
|
||||
nextLevelText.color = ResolveEquipmentColor(GetQualityColorIndex(nextLevelPreviewSO.level));
|
||||
}
|
||||
|
||||
private void RefreshMaterialRequirements()
|
||||
{
|
||||
ClearSpawnedMaterialItems();
|
||||
|
||||
if (mtrInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eqp_p_SO == null || need_mtrSO == null)
|
||||
{
|
||||
mtrInfo.text = "需要选择一个记忆";
|
||||
return;
|
||||
}
|
||||
|
||||
int level = eqp_p_SO.level;
|
||||
if (!IsLegalLevel(level))
|
||||
{
|
||||
mtrInfo.text = "非法等级";
|
||||
return;
|
||||
}
|
||||
|
||||
if (level >= 20)
|
||||
{
|
||||
mtrInfo.text = "<color=#FF67A4>梦醒时分记忆无法巡演</color>";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsTourEligibleLevel(level))
|
||||
{
|
||||
mtrInfo.text = BuildTourRequirementText(level);
|
||||
return;
|
||||
}
|
||||
|
||||
mtrInfo.text = string.Empty;
|
||||
SpawnTourMaterialItems(level);
|
||||
}
|
||||
|
||||
private void SpawnTourMaterialItems(int level)
|
||||
{
|
||||
if (mtrPrefab == null || merParent == null || need_mtrSO == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int materialRequired = need_mtrSO.GetBreakthroughMaterialRequired(level);
|
||||
int coinRequired = need_mtrSO.GetBreakthroughCoinsRequired(level);
|
||||
int memoryRequired = materialRequired;
|
||||
|
||||
if (materialRequired > 0 && need_mtrSO.breakthroughMaterial != null)
|
||||
{
|
||||
SpawnMaterialItem(
|
||||
need_mtrSO.breakthroughMaterial.consumableSprite,
|
||||
need_mtrSO.breakthroughMaterial.consumableName,
|
||||
materialRequired.ToString());
|
||||
}
|
||||
|
||||
if (coinRequired > 0)
|
||||
{
|
||||
SpawnMaterialItem(
|
||||
coinSprite,
|
||||
"Coins",
|
||||
coinRequired.ToString());
|
||||
}
|
||||
|
||||
if (memoryRequired > 0)
|
||||
{
|
||||
SpawnMaterialItem(
|
||||
memoryFragmentSprite,
|
||||
"记忆碎片",
|
||||
memoryRequired.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnMaterialItem(Sprite sprite, string displayName, string amountText)
|
||||
{
|
||||
GameObject instance = Instantiate(mtrPrefab, merParent);
|
||||
instance.SetActive(true);
|
||||
spawnedMaterialItems.Add(instance);
|
||||
|
||||
materialPrefab item = instance.GetComponent<materialPrefab>();
|
||||
if (item != null)
|
||||
{
|
||||
item.Bind(sprite, displayName, amountText, true, false, null);
|
||||
item.SetSelected(true);
|
||||
if (item.materialButton != null)
|
||||
{
|
||||
item.materialButton.interactable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshReasonWhy()
|
||||
{
|
||||
if (reasonWhy == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
reasonWhy.text = GetTourFailureReason();
|
||||
}
|
||||
|
||||
private void RefreshActionState()
|
||||
{
|
||||
if (yesIllusionButton == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
yesIllusionButton.interactable = string.IsNullOrEmpty(GetTourFailureReason());
|
||||
}
|
||||
|
||||
private string GetTourFailureReason()
|
||||
{
|
||||
if (eqp_p_SO == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (!IsLegalLevel(eqp_p_SO.level))
|
||||
{
|
||||
return "非法等级";
|
||||
}
|
||||
|
||||
if (eqp_p_SO.level >= 20)
|
||||
{
|
||||
return "梦醒时分记忆无法巡演";
|
||||
}
|
||||
|
||||
if (!IsTourEligibleLevel(eqp_p_SO.level))
|
||||
{
|
||||
return BuildTourRequirementText(eqp_p_SO.level);
|
||||
}
|
||||
|
||||
if (need_mtrSO == null)
|
||||
{
|
||||
return "未配置巡演规则";
|
||||
}
|
||||
|
||||
if (randomConfig == null)
|
||||
{
|
||||
return "未配置随机规则";
|
||||
}
|
||||
|
||||
int materialRequired = need_mtrSO.GetBreakthroughMaterialRequired(eqp_p_SO.level);
|
||||
int coinRequired = need_mtrSO.GetBreakthroughCoinsRequired(eqp_p_SO.level);
|
||||
int memoryRequired = materialRequired;
|
||||
|
||||
if (need_mtrSO.breakthroughMaterial == null)
|
||||
{
|
||||
return "未配置巡演材料";
|
||||
}
|
||||
|
||||
if (materialRequired > 0 && EquipmentConsumableLedger.EnsureInstance().GetCount(need_mtrSO.breakthroughMaterial.consumableKind) < materialRequired)
|
||||
{
|
||||
return "巡演材料不足";
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(coinRequired))
|
||||
{
|
||||
return "硬币不足";
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughMaterial(memoryRequired))
|
||||
{
|
||||
return "记忆碎片不足";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private void HandleYesIllusionClicked()
|
||||
{
|
||||
string failureReason = GetTourFailureReason();
|
||||
if (!string.IsNullOrEmpty(failureReason))
|
||||
{
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
|
||||
int level = eqp_p_SO.level;
|
||||
int materialRequired = need_mtrSO.GetBreakthroughMaterialRequired(level);
|
||||
int coinRequired = need_mtrSO.GetBreakthroughCoinsRequired(level);
|
||||
int memoryRequired = materialRequired;
|
||||
|
||||
if (!EquipmentConsumableLedger.EnsureInstance().TryConsume(need_mtrSO.breakthroughMaterial.consumableKind, materialRequired))
|
||||
{
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().TrySpendCoins(coinRequired))
|
||||
{
|
||||
EquipmentConsumableLedger.EnsureInstance().Add(need_mtrSO.breakthroughMaterial.consumableKind, materialRequired);
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().TrySpendMaterial(memoryRequired))
|
||||
{
|
||||
EquipmentConsumableLedger.EnsureInstance().Add(need_mtrSO.breakthroughMaterial.consumableKind, materialRequired);
|
||||
PlayerEconomyLedger.EnsureInstance().AddCoins(coinRequired);
|
||||
RefreshAll();
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyTourEffect();
|
||||
eqp_p_SO.level = Mathf.Clamp(eqp_p_SO.level + 1, 0, 20);
|
||||
PersistEquipment(eqp_p_SO);
|
||||
RefreshAllEquipBags();
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
private void ApplyTourEffect()
|
||||
{
|
||||
if (eqp_p_SO == null || randomConfig == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
randomConfig.NormalizeRuntimeData();
|
||||
|
||||
int skillRollIndex = GetTourSkillRollIndex(eqp_p_SO.level);
|
||||
bool skillHit = skillRollIndex >= 0 && UnityEngine.Random.value <= GetIllusionSkillChance(skillRollIndex);
|
||||
if (skillHit && eqp_p_SO.ia_skillID <= 0 && randomConfig.TryGetIllusionSkillId(out int illusionSkillId) && illusionSkillId > 0)
|
||||
{
|
||||
eqp_p_SO.ia_skillID = illusionSkillId;
|
||||
return;
|
||||
}
|
||||
|
||||
List<equipmentSO.EquipmentSpecialEffectType> candidates = BuildIllusionEffectPool();
|
||||
if (candidates.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
equipmentSO.EquipmentSpecialEffectType rolledType = candidates[UnityEngine.Random.Range(0, candidates.Count)];
|
||||
if (!randomConfig.TryGetIllusionEffectRange(rolledType, out float minValue, out float maxValue))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float rolledValue = RollGaussianValue(minValue, maxValue);
|
||||
MergeIllusionEffect(rolledType, rolledValue);
|
||||
}
|
||||
|
||||
private void MergeIllusionEffect(equipmentSO.EquipmentSpecialEffectType effectType, float rolledValue)
|
||||
{
|
||||
var effects = new List<equipmentSO.EquipmentSpecialEffect>();
|
||||
if (eqp_p_SO.illusionEffects != null)
|
||||
{
|
||||
for (int i = 0; i < eqp_p_SO.illusionEffects.Length; i++)
|
||||
{
|
||||
equipmentSO.EquipmentSpecialEffect effect = eqp_p_SO.illusionEffects[i];
|
||||
if (effect != null)
|
||||
{
|
||||
effects.Add(new equipmentSO.EquipmentSpecialEffect
|
||||
{
|
||||
effectType = effect.effectType,
|
||||
value = effect.value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < effects.Count; i++)
|
||||
{
|
||||
if (effects[i].effectType != effectType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float best = Mathf.Max(effects[i].value, rolledValue);
|
||||
effects[i].value = best + Mathf.Abs(best) * 0.2f;
|
||||
eqp_p_SO.illusionEffects = effects.ToArray();
|
||||
return;
|
||||
}
|
||||
|
||||
effects.Add(new equipmentSO.EquipmentSpecialEffect
|
||||
{
|
||||
effectType = effectType,
|
||||
value = rolledValue
|
||||
});
|
||||
eqp_p_SO.illusionEffects = effects.ToArray();
|
||||
}
|
||||
|
||||
private List<equipmentSO.EquipmentSpecialEffectType> BuildIllusionEffectPool()
|
||||
{
|
||||
var pool = new List<equipmentSO.EquipmentSpecialEffectType>();
|
||||
equipmentSO.EquipmentSpecialEffectType[] allTypes =
|
||||
{
|
||||
equipmentSO.EquipmentSpecialEffectType.MaxHp,
|
||||
equipmentSO.EquipmentSpecialEffectType.Attack,
|
||||
equipmentSO.EquipmentSpecialEffectType.MaxMana,
|
||||
equipmentSO.EquipmentSpecialEffectType.DamageResistance,
|
||||
equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency,
|
||||
equipmentSO.EquipmentSpecialEffectType.HitManaRecovery,
|
||||
equipmentSO.EquipmentSpecialEffectType.HitDamageMultiplier,
|
||||
equipmentSO.EquipmentSpecialEffectType.HpLoseBase
|
||||
};
|
||||
|
||||
for (int i = 0; i < allTypes.Length; i++)
|
||||
{
|
||||
if (randomConfig.TryGetIllusionEffectRange(allTypes[i], out _, out _))
|
||||
{
|
||||
pool.Add(allTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
private int GetTourSkillRollIndex(int level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case 4: return 0;
|
||||
case 9: return 1;
|
||||
case 14: return 2;
|
||||
case 19: return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private float GetIllusionSkillChance(int rollIndex)
|
||||
{
|
||||
switch (rollIndex)
|
||||
{
|
||||
case 0: return randomConfig != null ? randomConfig.ies01 : 0f;
|
||||
case 1: return randomConfig != null ? randomConfig.ies02 : 0f;
|
||||
case 2: return randomConfig != null ? randomConfig.ies03 : 0f;
|
||||
case 3: return randomConfig != null ? randomConfig.ies04 : 0f;
|
||||
default: return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private static float RollGaussianValue(float minValue, float maxValue)
|
||||
{
|
||||
if (Mathf.Approximately(minValue, maxValue))
|
||||
{
|
||||
return AvoidZero(minValue, maxValue, minValue);
|
||||
}
|
||||
|
||||
if (maxValue < minValue)
|
||||
{
|
||||
float cached = minValue;
|
||||
minValue = maxValue;
|
||||
maxValue = cached;
|
||||
}
|
||||
|
||||
float u1 = Mathf.Max(Mathf.Clamp01(UnityEngine.Random.value), 1e-6f);
|
||||
float u2 = Mathf.Clamp01(UnityEngine.Random.value);
|
||||
float standard = Mathf.Sqrt(-2f * Mathf.Log(u1)) * Mathf.Cos(2f * Mathf.PI * u2);
|
||||
float mean = (minValue + maxValue) * 0.5f;
|
||||
float deviation = (maxValue - minValue) / 6f;
|
||||
float rolled = Mathf.Clamp(mean + standard * deviation, minValue, maxValue);
|
||||
return AvoidZero(minValue, maxValue, rolled);
|
||||
}
|
||||
|
||||
private static float AvoidZero(float minValue, float maxValue, float value)
|
||||
{
|
||||
if (!Mathf.Approximately(value, 0f))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
if (minValue > 0f)
|
||||
{
|
||||
return minValue;
|
||||
}
|
||||
|
||||
if (maxValue < 0f)
|
||||
{
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
const float epsilon = 0.0001f;
|
||||
return UnityEngine.Random.value < 0.5f ? -epsilon : epsilon;
|
||||
}
|
||||
|
||||
private void ClearSpawnedMaterialItems()
|
||||
{
|
||||
for (int i = spawnedMaterialItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
GameObject instance = spawnedMaterialItems[i];
|
||||
if (instance == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(instance);
|
||||
}
|
||||
}
|
||||
|
||||
spawnedMaterialItems.Clear();
|
||||
}
|
||||
|
||||
private void DestroyPrevLevelPreview()
|
||||
{
|
||||
if (spawnedPrevLevelInstance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(spawnedPrevLevelInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(spawnedPrevLevelInstance);
|
||||
}
|
||||
|
||||
spawnedPrevLevelInstance = null;
|
||||
}
|
||||
|
||||
private void DestroyNextLevelPreview()
|
||||
{
|
||||
if (spawnedNextLevelInstance != null)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(spawnedNextLevelInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(spawnedNextLevelInstance);
|
||||
}
|
||||
}
|
||||
|
||||
spawnedNextLevelInstance = null;
|
||||
|
||||
if (nextLevelPreviewSO != null)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(nextLevelPreviewSO);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(nextLevelPreviewSO);
|
||||
}
|
||||
}
|
||||
|
||||
nextLevelPreviewSO = null;
|
||||
}
|
||||
|
||||
private static bool IsLegalLevel(int level)
|
||||
{
|
||||
return level >= 0 && level <= 20;
|
||||
}
|
||||
|
||||
private static bool IsTourEligibleLevel(int level)
|
||||
{
|
||||
return level == 4 || level == 9 || level == 14 || level == 19;
|
||||
}
|
||||
|
||||
private static string BuildTourRequirementText(int currentLevel)
|
||||
{
|
||||
int requiredLevel = GetNextTourRequiredLevel(currentLevel);
|
||||
return $"需要追忆等级{requiredLevel},当前追忆等级{Mathf.Max(0, currentLevel)}";
|
||||
}
|
||||
|
||||
private static int GetNextTourRequiredLevel(int currentLevel)
|
||||
{
|
||||
if (currentLevel < 4)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (currentLevel < 9)
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
if (currentLevel < 14)
|
||||
{
|
||||
return 14;
|
||||
}
|
||||
|
||||
if (currentLevel < 19)
|
||||
{
|
||||
return 19;
|
||||
}
|
||||
|
||||
return 19;
|
||||
}
|
||||
|
||||
private string ResolveTourStageName(int level)
|
||||
{
|
||||
if (!IsLegalLevel(level))
|
||||
{
|
||||
return "非法巡演罪";
|
||||
}
|
||||
|
||||
int index;
|
||||
if (level <= 4) index = 0;
|
||||
else if (level <= 9) index = 1;
|
||||
else if (level <= 14) index = 2;
|
||||
else if (level <= 19) index = 3;
|
||||
else index = 4;
|
||||
|
||||
if (illusionLevelName != null && index >= 0 && index < illusionLevelName.Length && !string.IsNullOrWhiteSpace(illusionLevelName[index]))
|
||||
{
|
||||
return illusionLevelName[index];
|
||||
}
|
||||
|
||||
return $"{Mathf.Max(0, level)}追忆等级";
|
||||
}
|
||||
|
||||
private Color ResolveEquipmentColor(int colorIndex)
|
||||
{
|
||||
if (eip == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
equipItemPrefab itemPrefab = eip.GetComponent<equipItemPrefab>();
|
||||
if (itemPrefab == null || itemPrefab.itemBtmColors == null || itemPrefab.itemBtmColors.Length == 0)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
int safeIndex = Mathf.Clamp(colorIndex, 0, itemPrefab.itemBtmColors.Length - 1);
|
||||
return itemPrefab.itemBtmColors[safeIndex];
|
||||
}
|
||||
|
||||
private static int GetQualityColorIndex(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 void PersistEquipment(equipmentSO equipment)
|
||||
{
|
||||
if (equipment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(equipment);
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void RefreshAllEquipBags()
|
||||
{
|
||||
equipBag[] bags = FindObjectsOfType<equipBag>(true);
|
||||
for (int i = 0; i < bags.Length; i++)
|
||||
{
|
||||
if (bags[i] != null)
|
||||
{
|
||||
bags[i].Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7097a43f5f23b24bb0773d0e00ac21e
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class equipTransfer : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 787cccb1d2e8da94396646b43e2ae853
|
||||
Reference in New Issue
Block a user