装备系统做了很多

This commit is contained in:
FloatGaming
2026-03-27 08:02:55 +08:00
parent dd205b6cb4
commit 538085b64f
119 changed files with 27552 additions and 1672 deletions
@@ -0,0 +1,510 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Bansonic
{
public static class equipmentGenerator
{
private const string EditorOutputFolder = "Assets/Resources/so/uEquip";
private const string RuntimeOutputFolder = "so/uEquip";
private static readonly List<equipmentSO> RuntimeGeneratedEquipments = new List<equipmentSO>();
private enum QualityRollMode { Default, High }
private class GeneratedEffectValue
{
public equipmentSO.EquipmentSpecialEffectType effectType;
public float value;
public int skillId;
}
public static IReadOnlyList<equipmentSO> GetRuntimeGeneratedEquipments() => RuntimeGeneratedEquipments;
public static List<equipmentSO> generateEquipment(
int quantity,
int level,
equipmentSO.EquipmentSkillType type,
float maxHp,
float attack,
float maxMana,
float damageResistance,
float scoreEfficiency,
equipmentSO.EquipmentSpecialEffect[] specialEffects,
equipmentSO.EquipmentSpecialEffect[] typeSameEffects,
equipmentSO.EquipmentSpecialEffect[] illusionEffects,
equipmentSO.EquipmentSpecialEffect[] maxLevelEffects,
int carriedSkillId,
equipmentSO template = null)
{
var results = new List<equipmentSO>(Mathf.Max(0, quantity));
for (int i = 0; i < Mathf.Max(0, quantity); i++)
{
equipmentSO generated = CreateBaseEquipment(template);
generated.name = BuildGeneratedName(type);
generated.skillType = type;
generated.level = Mathf.Max(0, level);
generated.maxHp.basicGain = maxHp;
generated.attack.basicGain = attack;
generated.maxMana.basicGain = maxMana;
generated.damageResistance.basicGain = damageResistance;
generated.scoreEfficiency.basicGain = scoreEfficiency;
generated.specialEffects = CloneEffects(specialEffects);
generated.typeSameEffects = CloneEffects(typeSameEffects);
generated.illusionEffects = CloneEffects(illusionEffects);
generated.maxLevelEffects = CloneEffects(maxLevelEffects);
generated.sa_skillID = Mathf.Max(0, carriedSkillId);
generated.ia_skillID = 0;
results.Add(Persist(generated));
}
return results;
}
public static equipmentSO GenerateFromSmeltReward(smeltStageRewardSO rewardSo, smeltStageRewardSO.SmeltStageRewardRequirement requirement)
{
if (rewardSo == null || requirement == null || rewardSo.rewardRandomConfig == null)
{
return null;
}
equipmentRandomConfigSO config = rewardSo.rewardRandomConfig;
config.NormalizeRuntimeData();
equipmentSO generated = CreateBaseEquipment(rewardSo.rewardTemplate);
generated.skillType = requirement.equipmentType == smeltStageRewardSO.equipType.selfChosenType
? requirement.chosenSkillType
: RollRandomSkillType();
generated.name = BuildGeneratedName(generated.skillType);
generated.level = 0;
generated.sa_skillID = 0;
generated.ia_skillID = 0;
QualityRollMode mode = requirement.qualityType == smeltStageRewardSO.attributeQuality.highQuality
? QualityRollMode.High
: QualityRollMode.Default;
ResetBasicGains(generated);
GenerateBasicAttributes(generated, config, mode);
GenerateTypeSameEffects(generated, config, mode);
GenerateSpecialEffects(generated, config, mode, requirement.skillRequirement == smeltStageRewardSO.skillOwned.mustHave);
GenerateIllusionEffects(generated, config, mode);
return Persist(generated);
}
private static equipmentSO CreateBaseEquipment(equipmentSO template)
{
equipmentSO generated = template != null ? UnityEngine.Object.Instantiate(template) : ScriptableObject.CreateInstance<equipmentSO>();
generated.hideFlags = HideFlags.None;
generated.maxHp ??= new equipmentSO.EquipmentStatTuning();
generated.attack ??= new equipmentSO.EquipmentStatTuning();
generated.maxMana ??= new equipmentSO.EquipmentStatTuning();
generated.damageResistance ??= new equipmentSO.EquipmentStatTuning();
generated.scoreEfficiency ??= new equipmentSO.EquipmentStatTuning();
generated.specialEffects ??= Array.Empty<equipmentSO.EquipmentSpecialEffect>();
generated.typeSameEffects ??= Array.Empty<equipmentSO.EquipmentSpecialEffect>();
generated.illusionEffects ??= Array.Empty<equipmentSO.EquipmentSpecialEffect>();
generated.maxLevelEffects ??= Array.Empty<equipmentSO.EquipmentSpecialEffect>();
return generated;
}
private static equipmentSO.EquipmentSkillType RollRandomSkillType()
{
Array values = Enum.GetValues(typeof(equipmentSO.EquipmentSkillType));
return (equipmentSO.EquipmentSkillType)values.GetValue(UnityEngine.Random.Range(0, values.Length));
}
private static void GenerateBasicAttributes(equipmentSO generated, equipmentRandomConfigSO config, QualityRollMode mode)
{
var candidates = new List<(equipmentSO.EquipmentStatTuning tuning, equipmentRandomConfigSO.RandomBasicAttributeType rangeType)>
{
(generated.maxHp, equipmentRandomConfigSO.RandomBasicAttributeType.MaxHp),
(generated.attack, equipmentRandomConfigSO.RandomBasicAttributeType.Attack),
(generated.maxMana, equipmentRandomConfigSO.RandomBasicAttributeType.MaxMana),
(generated.damageResistance, equipmentRandomConfigSO.RandomBasicAttributeType.DamageResistance),
(generated.scoreEfficiency, equipmentRandomConfigSO.RandomBasicAttributeType.ScoreEfficiency)
};
candidates.RemoveAll(e => e.tuning == null || !config.TryGetBasicRange(e.rangeType, out _, out _));
int count = Mathf.Clamp(config.randomBasicAttributeCount, 0, candidates.Count);
for (int i = 0; i < count; i++)
{
int pick = UnityEngine.Random.Range(0, candidates.Count);
var item = candidates[pick];
candidates.RemoveAt(pick);
config.TryGetBasicRange(item.rangeType, out float min, out float max);
item.tuning.basicGain = RollConfiguredValue(min, max, mode);
}
}
private static void GenerateTypeSameEffects(equipmentSO generated, equipmentRandomConfigSO config, QualityRollMode mode)
{
var selected = GetSelectedBasicAttributeTypes(generated);
var results = new List<equipmentSO.EquipmentSpecialEffect>();
foreach (var effectType in selected)
{
if (!TryMapToSpecialRange(effectType, out equipmentRandomConfigSO.RandomSpecialEffectType rangeType)) continue;
if (!config.TryGetTypeSameEffectRange(rangeType, out float min, out float max)) continue;
results.Add(new equipmentSO.EquipmentSpecialEffect { effectType = effectType, value = RollConfiguredValue(min, max, mode) });
}
generated.typeSameEffects = results.ToArray();
}
private static void GenerateSpecialEffects(equipmentSO generated, equipmentRandomConfigSO config, QualityRollMode mode, bool mustHaveSkill)
{
int count = RollSpecialEffectCount(config);
var pool = BuildSpecialEffectPool(generated, config);
var generatedEffects = new List<GeneratedEffectValue>();
if (pool.Count == 0 || count <= 0)
{
generated.specialEffects = Array.Empty<equipmentSO.EquipmentSpecialEffect>();
generated.sa_skillID = 0;
return;
}
for (int i = 0; i < count; i++)
{
var effectType = pool[UnityEngine.Random.Range(0, pool.Count)];
if (!TryMapToSpecialRange(effectType, out equipmentRandomConfigSO.RandomSpecialEffectType rangeType)) continue;
if (!config.TryGetSpecialRange(rangeType, out float min, out float max)) continue;
generatedEffects.Add(new GeneratedEffectValue { effectType = effectType, value = RollConfiguredValue(min, max, mode) });
}
ResolveDuplicateEffects(generatedEffects);
bool shouldGenerateSkill = mustHaveSkill || UnityEngine.Random.value <= config.sesp;
if (shouldGenerateSkill && generatedEffects.Count > 0 && config.TryGetSpecialSkillId(generated.skillType, out int skillId) && skillId > 0)
{
int replace = UnityEngine.Random.Range(0, generatedEffects.Count);
generatedEffects[replace] = new GeneratedEffectValue { effectType = equipmentSO.EquipmentSpecialEffectType.Skill, value = 0f, skillId = skillId };
generated.sa_skillID = skillId;
}
else
{
generated.sa_skillID = 0;
}
generated.specialEffects = BuildGeneratedEffects(generatedEffects);
}
private static void GenerateIllusionEffects(equipmentSO generated, equipmentRandomConfigSO config, QualityRollMode mode)
{
if (generated.illusionEffects == null || generated.illusionEffects.Length == 0)
{
generated.ia_skillID = 0;
return;
}
int count = Mathf.Min(RollSpecialEffectCount(config), generated.illusionEffects.Length);
bool hasTemplateSkill = false;
var valuePool = new List<equipmentSO.EquipmentSpecialEffect>();
foreach (var effect in generated.illusionEffects)
{
if (effect == null) continue;
if (effect.effectType == equipmentSO.EquipmentSpecialEffectType.Skill) { hasTemplateSkill = true; continue; }
if (TryMapToIllusionRange(effect.effectType, out _)) valuePool.Add(effect);
}
var results = new List<equipmentSO.EquipmentSpecialEffect>();
generated.ia_skillID = 0;
for (int i = 0; i < count; i++)
{
bool shouldSkill = hasTemplateSkill && UnityEngine.Random.value <= GetIllusionSkillChance(config, i);
if (shouldSkill && config.TryGetIllusionSkillId(out int illusionSkillId) && illusionSkillId > 0)
{
results.Add(new equipmentSO.EquipmentSpecialEffect { effectType = equipmentSO.EquipmentSpecialEffectType.Skill, value = 0f });
generated.ia_skillID = illusionSkillId;
hasTemplateSkill = false;
continue;
}
if (valuePool.Count == 0) break;
int pick = UnityEngine.Random.Range(0, valuePool.Count);
var effect = valuePool[pick];
valuePool.RemoveAt(pick);
if (!TryMapToIllusionRange(effect.effectType, out equipmentRandomConfigSO.RandomIllusionEffectType rangeType)) { i--; continue; }
if (!config.TryGetIllusionRange(rangeType, out float min, out float max)) { i--; continue; }
results.Add(new equipmentSO.EquipmentSpecialEffect { effectType = effect.effectType, value = RollConfiguredValue(min, max, mode) });
}
generated.illusionEffects = results.ToArray();
}
private static List<equipmentSO.EquipmentSpecialEffectType> BuildSpecialEffectPool(equipmentSO generated, equipmentRandomConfigSO config)
{
var pool = new List<equipmentSO.EquipmentSpecialEffectType>();
var selected = GetSelectedBasicAttributeTypes(generated);
equipmentSO.EquipmentSpecialEffectType[] allTypes =
{
equipmentSO.EquipmentSpecialEffectType.MaxHp,
equipmentSO.EquipmentSpecialEffectType.Attack,
equipmentSO.EquipmentSpecialEffectType.MaxMana,
equipmentSO.EquipmentSpecialEffectType.DamageResistance,
equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency
};
if (generated.enableTypeSameEffects && selected.Count > 0)
{
foreach (var effectType in selected)
{
if (TryMapToSpecialRange(effectType, out equipmentRandomConfigSO.RandomSpecialEffectType rangeType) && config.TryGetSpecialRange(rangeType, out _, out _))
pool.Add(effectType);
}
return pool;
}
for (int i = 0; i < allTypes.Length; i++)
{
if (TryMapToSpecialRange(allTypes[i], out equipmentRandomConfigSO.RandomSpecialEffectType rangeType) && config.TryGetSpecialRange(rangeType, out _, out _))
pool.Add(allTypes[i]);
}
return pool;
}
private static HashSet<equipmentSO.EquipmentSpecialEffectType> GetSelectedBasicAttributeTypes(equipmentSO target)
{
var selected = new HashSet<equipmentSO.EquipmentSpecialEffectType>();
if (target.maxHp != null && !Mathf.Approximately(target.maxHp.basicGain, 0f)) selected.Add(equipmentSO.EquipmentSpecialEffectType.MaxHp);
if (target.attack != null && !Mathf.Approximately(target.attack.basicGain, 0f)) selected.Add(equipmentSO.EquipmentSpecialEffectType.Attack);
if (target.maxMana != null && !Mathf.Approximately(target.maxMana.basicGain, 0f)) selected.Add(equipmentSO.EquipmentSpecialEffectType.MaxMana);
if (target.damageResistance != null && !Mathf.Approximately(target.damageResistance.basicGain, 0f)) selected.Add(equipmentSO.EquipmentSpecialEffectType.DamageResistance);
if (target.scoreEfficiency != null && !Mathf.Approximately(target.scoreEfficiency.basicGain, 0f)) selected.Add(equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency);
return selected;
}
private static int RollSpecialEffectCount(equipmentRandomConfigSO config)
{
float roll = UnityEngine.Random.value;
if (roll <= config.se01p) return 1;
if (roll <= config.se01p + config.se02p) return 2;
return 3;
}
private static float GetIllusionSkillChance(equipmentRandomConfigSO config, int slotIndex) => slotIndex switch
{
0 => config.ies01,
1 => config.ies02,
2 => config.ies03,
_ => config.ies04,
};
private static equipmentSO Persist(equipmentSO generated)
{
if (generated == null) return null;
#if UNITY_EDITOR
if (!Application.isPlaying)
{
EnsureEditorOutputFolderExists();
string assetPath = Path.Combine(EditorOutputFolder, generated.name + ".asset").Replace("\\", "/");
AssetDatabase.CreateAsset(generated, assetPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
equipmentSO persisted = AssetDatabase.LoadAssetAtPath<equipmentSO>(assetPath);
if (persisted != null)
{
RuntimeGeneratedEquipments.RemoveAll(item => item == null || item.name == persisted.name);
RuntimeGeneratedEquipments.Add(persisted);
return persisted;
}
}
#endif
RuntimeGeneratedEquipments.RemoveAll(item => item == null || item.name == generated.name);
RuntimeGeneratedEquipments.Add(generated);
return generated;
}
private static string BuildGeneratedName(equipmentSO.EquipmentSkillType type)
{
int typeIndex = (int)type;
string dateStamp = DateTime.Now.ToString("yyyyMMdd");
int nextId = GetNextGeneratedId();
return $"type{typeIndex}_{dateStamp}_{nextId:D8}";
}
private static int GetNextGeneratedId()
{
int maxId = 0;
for (int i = 0; i < RuntimeGeneratedEquipments.Count; i++)
{
if (RuntimeGeneratedEquipments[i] != null)
{
TryUpdateMaxId(RuntimeGeneratedEquipments[i].name, ref maxId);
}
}
#if UNITY_EDITOR
string absoluteFolder = Path.GetFullPath(EditorOutputFolder);
if (Directory.Exists(absoluteFolder))
{
string[] files = Directory.GetFiles(absoluteFolder, "*.asset", SearchOption.TopDirectoryOnly);
for (int i = 0; i < files.Length; i++)
{
TryUpdateMaxId(Path.GetFileNameWithoutExtension(files[i]), ref maxId);
}
}
#else
equipmentSO[] resources = Resources.LoadAll<equipmentSO>(RuntimeOutputFolder);
for (int i = 0; i < resources.Length; i++)
{
if (resources[i] != null)
{
TryUpdateMaxId(resources[i].name, ref maxId);
}
}
#endif
return maxId + 1;
}
private static void TryUpdateMaxId(string fileName, ref int maxId)
{
if (string.IsNullOrWhiteSpace(fileName)) return;
int lastUnderscore = fileName.LastIndexOf('_');
if (lastUnderscore < 0 || lastUnderscore >= fileName.Length - 1) return;
string idPart = fileName.Substring(lastUnderscore + 1);
if (int.TryParse(idPart, out int parsedId) && parsedId > maxId)
{
maxId = parsedId;
}
}
private static equipmentSO.EquipmentSpecialEffect[] CloneEffects(equipmentSO.EquipmentSpecialEffect[] source)
{
if (source == null || source.Length == 0) return Array.Empty<equipmentSO.EquipmentSpecialEffect>();
var clone = new equipmentSO.EquipmentSpecialEffect[source.Length];
for (int i = 0; i < source.Length; i++)
{
equipmentSO.EquipmentSpecialEffect effect = source[i];
clone[i] = effect == null ? null : new equipmentSO.EquipmentSpecialEffect { effectType = effect.effectType, value = effect.value };
}
return clone;
}
private static void ResetBasicGains(equipmentSO generated)
{
if (generated.maxHp != null) generated.maxHp.basicGain = 0f;
if (generated.attack != null) generated.attack.basicGain = 0f;
if (generated.maxMana != null) generated.maxMana.basicGain = 0f;
if (generated.damageResistance != null) generated.damageResistance.basicGain = 0f;
if (generated.scoreEfficiency != null) generated.scoreEfficiency.basicGain = 0f;
}
private static bool TryMapToSpecialRange(equipmentSO.EquipmentSpecialEffectType effectType, out equipmentRandomConfigSO.RandomSpecialEffectType mappedType)
{
switch (effectType)
{
case equipmentSO.EquipmentSpecialEffectType.MaxHp: mappedType = equipmentRandomConfigSO.RandomSpecialEffectType.MaxHp; return true;
case equipmentSO.EquipmentSpecialEffectType.Attack: mappedType = equipmentRandomConfigSO.RandomSpecialEffectType.Attack; return true;
case equipmentSO.EquipmentSpecialEffectType.MaxMana: mappedType = equipmentRandomConfigSO.RandomSpecialEffectType.MaxMana; return true;
case equipmentSO.EquipmentSpecialEffectType.DamageResistance: mappedType = equipmentRandomConfigSO.RandomSpecialEffectType.DamageResistance; return true;
case equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency: mappedType = equipmentRandomConfigSO.RandomSpecialEffectType.ScoreEfficiency; return true;
default: mappedType = default; return false;
}
}
private static bool TryMapToIllusionRange(equipmentSO.EquipmentSpecialEffectType effectType, out equipmentRandomConfigSO.RandomIllusionEffectType mappedType)
{
switch (effectType)
{
case equipmentSO.EquipmentSpecialEffectType.MaxHp: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.MaxHp; return true;
case equipmentSO.EquipmentSpecialEffectType.Attack: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.Attack; return true;
case equipmentSO.EquipmentSpecialEffectType.MaxMana: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.MaxMana; return true;
case equipmentSO.EquipmentSpecialEffectType.DamageResistance: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.DamageResistance; return true;
case equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.ScoreEfficiency; return true;
case equipmentSO.EquipmentSpecialEffectType.HitManaRecovery: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.HitManaRecovery; return true;
case equipmentSO.EquipmentSpecialEffectType.HitDamageMultiplier: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.HitDamageMultiplier; return true;
case equipmentSO.EquipmentSpecialEffectType.HpLoseBase: mappedType = equipmentRandomConfigSO.RandomIllusionEffectType.HpLoseBase; return true;
default: mappedType = default; return false;
}
}
private static equipmentSO.EquipmentSpecialEffect[] BuildGeneratedEffects(List<GeneratedEffectValue> generatedEffects)
{
if (generatedEffects == null || generatedEffects.Count == 0) return Array.Empty<equipmentSO.EquipmentSpecialEffect>();
var results = new List<equipmentSO.EquipmentSpecialEffect>(generatedEffects.Count);
for (int i = 0; i < generatedEffects.Count; i++)
{
GeneratedEffectValue value = generatedEffects[i];
results.Add(new equipmentSO.EquipmentSpecialEffect
{
effectType = value.effectType,
value = value.effectType == equipmentSO.EquipmentSpecialEffectType.Skill ? 0f : value.value
});
}
return results.ToArray();
}
private static float RollConfiguredValue(float minValue, float maxValue, QualityRollMode mode)
{
return mode == QualityRollMode.High ? RollHighQualityValue(minValue, maxValue) : RollBiasedValue(minValue, maxValue);
}
private static float RollHighQualityValue(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 span = maxValue - minValue;
return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(maxValue - span * 0.2f, maxValue));
}
private static float RollBiasedValue(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 span = maxValue - minValue;
float roll = UnityEngine.Random.value;
if (roll <= 0.05f) return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(minValue, minValue + span * 0.1f));
if (roll >= 0.95f) return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(maxValue - span * 0.1f, maxValue));
return AvoidZero(minValue, maxValue, Mathf.Lerp(minValue, maxValue, SampleClampedGaussian01()));
}
private static float SampleClampedGaussian01()
{
float u1 = Mathf.Max(Mathf.Clamp01(UnityEngine.Random.value), 1e-6f);
float u2 = Mathf.Clamp01(UnityEngine.Random.value);
float standardNormal = Mathf.Sqrt(-2f * Mathf.Log(u1)) * Mathf.Cos(2f * Mathf.PI * u2);
return Mathf.Clamp01(0.5f + standardNormal * 0.18f);
}
private static void ResolveDuplicateEffects(List<GeneratedEffectValue> effects)
{
if (effects == null || effects.Count <= 1) return;
var bestByType = new Dictionary<equipmentSO.EquipmentSpecialEffectType, GeneratedEffectValue>();
for (int i = 0; i < effects.Count; i++)
{
GeneratedEffectValue candidate = effects[i];
if (!bestByType.TryGetValue(candidate.effectType, out GeneratedEffectValue existing))
{
bestByType[candidate.effectType] = candidate;
continue;
}
bestByType[candidate.effectType] = ChoosePreferred(existing, candidate);
}
effects.Clear();
foreach (GeneratedEffectValue value in bestByType.Values) effects.Add(value);
}
private static GeneratedEffectValue ChoosePreferred(GeneratedEffectValue left, GeneratedEffectValue right)
{
bool leftNegative = left.value < 0f;
bool rightNegative = right.value < 0f;
if (leftNegative && rightNegative) return left.value <= right.value ? left : right;
if (!leftNegative && !rightNegative) return left.value >= right.value ? left : right;
return Mathf.Abs(left.value) >= Mathf.Abs(right.value) ? left : right;
}
private static float AvoidZero(float minValue, float maxValue, float value)
{
if (!Mathf.Approximately(value, 0f)) return value;
if (minValue > 0f || maxValue < 0f) return value;
float epsilon = Mathf.Min(0.0001f, Mathf.Max(Mathf.Abs(minValue), Mathf.Abs(maxValue), 0.0001f));
return UnityEngine.Random.value < 0.5f ? -epsilon : epsilon;
}
#if UNITY_EDITOR
private static void EnsureEditorOutputFolderExists()
{
if (AssetDatabase.IsValidFolder(EditorOutputFolder)) return;
if (!AssetDatabase.IsValidFolder("Assets/Resources")) AssetDatabase.CreateFolder("Assets", "Resources");
if (!AssetDatabase.IsValidFolder("Assets/Resources/so")) AssetDatabase.CreateFolder("Assets/Resources", "so");
if (!AssetDatabase.IsValidFolder(EditorOutputFolder)) AssetDatabase.CreateFolder("Assets/Resources/so", "uEquip");
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f447d77431ab23b48bee1d5ffd302cd6
@@ -0,0 +1,115 @@
%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: fbec1eb650c88494083b6b5e079cc4a2, type: 3}
m_Name: EquipmentRandomConfig
m_EditorClassIdentifier:
randomBasicAttributeCount: 2
basicAttributeRanges:
- attributeType: 0
minValue: -0.02
maxValue: 0.1
- attributeType: 1
minValue: -0.02
maxValue: 0.1
- attributeType: 2
minValue: -0.02
maxValue: 0.1
- attributeType: 3
minValue: -0.02
maxValue: 0.1
- attributeType: 4
minValue: -0.02
maxValue: 0.1
onlyProduceSameTypeAttributes: 0
se01p: 0.6
se02p: 0.35
se03p: 0.05
sesp: 0.05
ies01: 0.2
ies02: 0.35
ies03: 0.5
ies04: 0.65
specialEffectRanges:
- effectType: 0
minValue: -10
maxValue: 50
- effectType: 1
minValue: -3
maxValue: 8
- effectType: 2
minValue: -25
maxValue: 25
- effectType: 3
minValue: -0.005
maxValue: 0.01
- effectType: 4
minValue: -0.005
maxValue: 0.01
typeSameEffectRanges:
- effectType: 0
minValue: 0.005
maxValue: 0.005
- effectType: 1
minValue: 0.005
maxValue: 0.005
- effectType: 2
minValue: 0.005
maxValue: 0.005
- effectType: 3
minValue: 0.005
maxValue: 0.005
- effectType: 4
minValue: 0.005
maxValue: 0.005
illusionEffectRanges:
- effectType: 0
minValue: 0
maxValue: 0
- effectType: 1
minValue: 0
maxValue: 0
- effectType: 2
minValue: 0
maxValue: 0
- effectType: 3
minValue: 0
maxValue: 0
- effectType: 4
minValue: 0
maxValue: 0
- effectType: 5
minValue: 0
maxValue: 0
- effectType: 6
minValue: 0
maxValue: 0
- effectType: 7
minValue: 0
maxValue: 0
specialSkillPool:
- skillType: 0
skillIds: 69c7c9016ac7c9016bc7c9016cc7c901
- skillType: 1
skillIds:
- skillType: 2
skillIds:
- skillType: 3
skillIds:
- skillType: 4
skillIds:
- skillType: 5
skillIds:
- skillType: 6
skillIds:
- skillType: 7
skillIds:
illusionSkillPool: 79eec9017aeec9017beec9017ceec901
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ca394ccb04190524fb487491eedb36e7
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
+45
View File
@@ -0,0 +1,45 @@
%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: ccc48e40c2584d64ab55b464a05cda93, type: 3}
m_Name: EquipmentTemplate
m_EditorClassIdentifier:
skillType: 0
level: 1
tierNameConfig: {fileID: 11400000, guid: dd40d174875037e439647e54cf81eab1, type: 2}
maxHp:
basicGain: -0
cultivationInterval: 0.005
attack:
basicGain: 0
cultivationInterval: 0.005
maxMana:
basicGain: 0
cultivationInterval: 0.005
damageResistance:
basicGain: 0
cultivationInterval: 0.005
scoreEfficiency:
basicGain: 0
cultivationInterval: 0.005
specialEffects:
- effectType: 0
value: 0
enableTypeSameEffects: 0
typeSameEffects: []
illusionEffects:
- effectType: 0
value: 0
- effectType: 0
value: 0
maxLevelEffects: []
sa_skillID: 0
ia_skillID: 0
@@ -0,0 +1,151 @@
%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: 8dc6271282c80ec4387e3734f1157285, type: 3}
m_Name: EquipmentTierNameConfig
m_EditorClassIdentifier:
namingSets:
- skillType: 0
stagePresentations:
- tierName: "\u9898\u6D77\u7834\u6D6A"
equipmentSprite: {fileID: 21300000, guid: 2ca0f01bbfea44aacb78e56edc48fc71, type: 3}
tierDescription: "\u7834\u9898\u5982\u7834\u6D6A\uFF0C\u601D\u8DEF\u6108\u6218\u6108\u5F00\u3002"
- tierName: "\u9898\u6E0A\u65AD\u6F6E"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u88C2\u6D77\u65A9"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u6CA7\u6E9F\u6740\u53F7"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u9010\u6D6A\u6781\u610F"
equipmentSprite: {fileID: 21300000, guid: b20bb1f822693463499065afa6c27f4c, type: 3}
tierDescription:
- skillType: 1
stagePresentations:
- tierName: "\u8BDB\u6740\u53F7"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u6E05\u5F02\u5203"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u65AD\u9006\u950B"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u706D\u5F02\u88C1\u51B3"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u7EDD\u706D\u7981\u4EE4"
equipmentSprite: {fileID: 21300000, guid: 0d613dfdfe017447c99d4a4c509cbf25, type: 3}
tierDescription: "\u88C1\u51B3\u964D\u4E34\uFF0C\u4E00\u5207\u76EE\u6807\u5F52\u96F6"
- skillType: 2
stagePresentations:
- tierName: "\u540C\u4E50\u5951"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u5171\u8C0B\u73AF"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u534F\u5F8B\u5370"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u9038\u4E50\u5171\u632F"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u5929\u548C\u540C\u5951"
equipmentSprite: {fileID: 0}
tierDescription:
- skillType: 3
stagePresentations:
- tierName: "\u7CBE\u4FEE\u4EF6"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u6781\u81F4\u6838"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u5B8C\u6574\u4F53"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u81F3\u4E0A\u6784\u578B"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u5B8C\u7F8E\u7EC8\u5F0F"
equipmentSprite: {fileID: 0}
tierDescription:
- skillType: 4
stagePresentations:
- tierName: "\u9759\u5FC3\u8BC0"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u517B\u6C14\u6CD5"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u6F84\u660E\u5883"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u5FC3\u517B\u5F52\u4E00"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u65E0\u5C18\u771F\u5883"
equipmentSprite: {fileID: 0}
tierDescription:
- skillType: 5
stagePresentations:
- tierName: "\u540C\u5FC3\u5370"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u534F\u529B\u73AF"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u5171\u9E23\u9635"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u4F17\u5FD7\u58C1\u5792"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u4E0D\u7834\u57CE\u57DF"
equipmentSprite: {fileID: 0}
tierDescription:
- skillType: 6
stagePresentations:
- tierName: "\u66B4\u6012"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u72C2\u6012"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u5D29\u89E3"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u5168\u529B\u4E00\u51FB"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u661F\u8FB0\u8D2F\u7A7F"
equipmentSprite: {fileID: 0}
tierDescription:
- skillType: 7
stagePresentations:
- tierName: "\u521D\u6784"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u91CD\u6784"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u4E8C\u91CD\u6784"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u4E09\u91CD\u6784"
equipmentSprite: {fileID: 0}
tierDescription:
- tierName: "\u68A6\u9192\xB7\u91CD\u91CD\u6784"
equipmentSprite: {fileID: 0}
tierDescription:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dd40d174875037e439647e54cf81eab1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
-61
View File
@@ -1,61 +0,0 @@
%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: ccc48e40c2584d64ab55b464a05cda93, type: 3}
m_Name: NewEquipment
m_EditorClassIdentifier:
level: 1
tierPresentations:
- tierName:
tierIcon: {fileID: 0}
tierDescription:
- tierName:
tierIcon: {fileID: 0}
tierDescription:
- tierName:
tierIcon: {fileID: 0}
tierDescription:
- tierName:
tierIcon: {fileID: 0}
tierDescription:
- tierName:
tierIcon: {fileID: 0}
tierDescription:
maxHp:
basicGain: -0
randomRangeStart: 0
randomRangeEnd: 0
cultivationInterval: 0
attack:
basicGain: 0
randomRangeStart: 0
randomRangeEnd: 0
cultivationInterval: 0
maxMana:
basicGain: 0
randomRangeStart: 0
randomRangeEnd: 0
cultivationInterval: 0
damageResistance:
basicGain: 0
randomRangeStart: 0
randomRangeEnd: 0
cultivationInterval: 0
scoreEfficiency:
basicGain: 0
randomRangeStart: 0
randomRangeEnd: 0
cultivationInterval: 0
specialEffects:
- effectType: 0
value: 0
displayName:
displayIcon: {fileID: 0}
+640
View File
@@ -0,0 +1,640 @@
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)");
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b550d7e8a06c6214e8c7a3676812680e
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 00982b98d18fbe94cb371f5451f6e244
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+208
View File
@@ -0,0 +1,208 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1092441655972436382
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3607037587688041023}
- component: {fileID: 9205501567152241640}
m_Layer: 5
m_Name: eqpmtSkillPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3607037587688041023
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1092441655972436382}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 787721615639597164}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &9205501567152241640
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1092441655972436382}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 099deb535165a1d4bad59c389ff3e3dd, type: 3}
m_Name:
m_EditorClassIdentifier:
esIcon: {fileID: 7288798217434866852}
esName: {fileID: 4430962521111267411}
--- !u!1 &5588761580184731607
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 787721615639597164}
- component: {fileID: 9009718483299206920}
- component: {fileID: 7288798217434866852}
m_Layer: 5
m_Name: profile
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &787721615639597164
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5588761580184731607}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 80767430313895055}
m_Father: {fileID: 3607037587688041023}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -42.5, y: 3.6}
m_SizeDelta: {x: 15, y: 15}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &9009718483299206920
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5588761580184731607}
m_CullTransparentMesh: 1
--- !u!114 &7288798217434866852
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5588761580184731607}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &6277739774383891644
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 80767430313895055}
- component: {fileID: 7417280378955229841}
- component: {fileID: 4430962521111267411}
m_Layer: 5
m_Name: name
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &80767430313895055
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6277739774383891644}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 787721615639597164}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 119.985, y: 0}
m_SizeDelta: {x: 209.971, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7417280378955229841
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6277739774383891644}
m_CullTransparentMesh: 1
--- !u!114 &4430962521111267411
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6277739774383891644}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.8160377, g: 1, b: 0.9974971, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 0
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 3
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u8BB0\u5FC6\u7279\u6548\u6280\u80FD\uFF1A\u5F6C\u4E4B\u9E21\u86CB\u5B66\u8BF4"
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b4fd92d46a6409344a8e1bc658b4b4e9
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+30
View File
@@ -0,0 +1,30 @@
using UnityEngine;
using UnityEngine.UI;
public class eqpmtSkillPrefabItem : MonoBehaviour
{
public int skillId;
public Image skillIcon;
public Text skillName;
public Text skillIdText;
public void Bind(int id)
{
skillId = id;
if (skillName != null)
{
skillName.text = $"Skill {skillId}";
}
if (skillIdText != null)
{
skillIdText.text = skillId.ToString();
}
if (skillIcon != null)
{
skillIcon.enabled = skillIcon.sprite != null;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3709c3fb67e5f5e49a0831fa2db0e621
+200
View File
@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Bansonic;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class equipBag : MonoBehaviour
{
[Header("prefab")]
public GameObject eqpmtItemPrefab;
public Transform eqpmtItemParent;
[Header("source paths")]
public string runtimeEquipmentFolder = "so/uEquip";
public string editorEquipmentFolder = "Assets/Resources/so/uEquip";
private readonly List<GameObject> spawnedItems = new List<GameObject>();
private void Start()
{
Rebuild();
}
private void OnEnable()
{
Rebuild();
}
public void Rebuild()
{
ClearSpawnedItems();
if (eqpmtItemPrefab == null || eqpmtItemParent == null)
{
return;
}
equipmentSO[] equipments = LoadEquipments();
if (equipments == null || equipments.Length == 0)
{
return;
}
equipments = equipments
.Where(equipment => equipment != null
&& !equipSmelt.IsEquipmentAssignedToSmeltPool(equipment)
&& !equipSmelt.IsEquipmentConsumedBySmelt(equipment))
.ToArray();
Array.Sort(equipments, CompareEquipments);
for (int i = 0; i < equipments.Length; i++)
{
equipmentSO equipment = equipments[i];
if (equipment == null)
{
continue;
}
GameObject instance = Instantiate(eqpmtItemPrefab, eqpmtItemParent);
instance.name = string.IsNullOrWhiteSpace(equipment.GetCurrentTierDisplayName())
? equipment.name
: equipment.GetCurrentTierDisplayName();
equipItemPrefab item = instance.GetComponent<equipItemPrefab>();
if (item != null)
{
item.Bind(equipment, HandleEquipmentClicked);
}
spawnedItems.Add(instance);
}
}
private equipmentSO[] LoadEquipments()
{
var results = new List<equipmentSO>();
#if UNITY_EDITOR
if (!Application.isPlaying)
{
results.AddRange(LoadEditorEquipments());
}
else
#endif
{
results.AddRange(Resources.LoadAll<equipmentSO>(runtimeEquipmentFolder)
.Where(equipment => equipment != null));
}
IReadOnlyList<equipmentSO> runtimeGenerated = equipmentGenerator.GetRuntimeGeneratedEquipments();
if (runtimeGenerated != null)
{
for (int i = 0; i < runtimeGenerated.Count; i++)
{
equipmentSO equipment = runtimeGenerated[i];
if (equipment != null && !results.Contains(equipment))
{
results.Add(equipment);
}
}
}
return results
.Where(equipment => equipment != null)
.ToArray();
}
#if UNITY_EDITOR
private equipmentSO[] LoadEditorEquipments()
{
if (string.IsNullOrWhiteSpace(editorEquipmentFolder) || !AssetDatabase.IsValidFolder(editorEquipmentFolder))
{
return Array.Empty<equipmentSO>();
}
string[] guids = AssetDatabase.FindAssets("t:equipmentSO", new[] { editorEquipmentFolder });
var result = new List<equipmentSO>(guids.Length);
for (int i = 0; i < guids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
equipmentSO equipment = AssetDatabase.LoadAssetAtPath<equipmentSO>(path);
if (equipment != null)
{
result.Add(equipment);
}
}
return result.ToArray();
}
#endif
private void HandleEquipmentClicked(equipmentSO equipment)
{
if (equipment == null)
{
return;
}
}
private void ClearSpawnedItems()
{
if (eqpmtItemParent != null)
{
for (int i = eqpmtItemParent.childCount - 1; i >= 0; i--)
{
Transform child = eqpmtItemParent.GetChild(i);
if (child == null)
{
continue;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(child.gameObject);
}
else
#endif
{
Destroy(child.gameObject);
}
}
}
spawnedItems.Clear();
}
private static int CompareEquipments(equipmentSO left, equipmentSO right)
{
if (left == right)
{
return 0;
}
if (left == null)
{
return 1;
}
if (right == null)
{
return -1;
}
int levelCompare = right.level.CompareTo(left.level);
if (levelCompare != 0)
{
return levelCompare;
}
string leftName = left.GetCurrentTierDisplayName();
string rightName = right.GetCurrentTierDisplayName();
return string.Compare(leftName, rightName, StringComparison.Ordinal);
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ad117e8f9c5167944bbae4e991210308
+528
View File
@@ -0,0 +1,528 @@
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class equipItemPrefab : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
{
[Header("so")]
public equipmentSO itemSO;
[Header("info")]
public Image itemBtm;
public Color[] itemBtmColors;
public Image itemProfileIcon;
public string itemType;
public string itemName;
public Button itemButton;
[Header("description popup")]
public GameObject eqpmtDesPrefab;
public Transform popupParent;
public float popupHorizontalOffset = 40f;
[Header("events")]
public UnityEvent<equipmentSO> onItemClicked;
[Header("interaction")]
public bool allowDrag = true;
public bool allowQuickTransfer = true;
private Action<equipmentSO> clickHandler;
private GameObject spawnedDescription;
private bool suppressNextClick;
private Canvas rootCanvas;
private Camera uiCamera;
private GameObject dragGhost;
private RectTransform dragGhostRect;
private bool isDraggingWithLeftButton;
private void Awake()
{
if (itemButton == null)
{
itemButton = GetComponent<Button>();
}
if (itemButton != null)
{
itemButton.onClick.RemoveListener(HandleClicked);
itemButton.onClick.AddListener(HandleClicked);
}
rootCanvas = GetComponentInParent<Canvas>();
if (rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay)
{
uiCamera = rootCanvas.worldCamera;
}
}
public void Bind(equipmentSO so, Action<equipmentSO> onClick = null)
{
itemSO = so;
clickHandler = onClick;
if (itemSO == null)
{
ApplyProfileSprite(null);
ApplyBottomColor(0);
return;
}
equipmentSO.EquipmentTierPresentation presentation = itemSO.GetCurrentTierPresentation();
Sprite displaySprite = presentation != null ? presentation.equipmentSprite : null;
ApplyProfileSprite(displaySprite);
ApplyBottomColor(GetQualityColorIndex(itemSO.level));
}
private void HandleClicked()
{
if (suppressNextClick)
{
suppressNextClick = false;
return;
}
if (itemSO == null)
{
return;
}
ToggleDescriptionPopup();
clickHandler?.Invoke(itemSO);
onItemClicked?.Invoke(itemSO);
}
private void ToggleDescriptionPopup()
{
if (eqpmtDesPrefab == null)
{
return;
}
if (spawnedDescription != null)
{
Destroy(spawnedDescription);
spawnedDescription = null;
return;
}
Transform targetParent = ResolvePopupParent();
if (targetParent == null)
{
return;
}
spawnedDescription = Instantiate(eqpmtDesPrefab, targetParent);
spawnedDescription.name = $"{itemSO.name}_Description";
spawnedDescription.SetActive(true);
spawnedDescription.transform.SetAsLastSibling();
eqpmtDesPrefab description = spawnedDescription.GetComponent<eqpmtDesPrefab>();
if (description != null)
{
description.IgnoreCloseUntilClickReleased();
description.Bind(itemSO);
}
PositionPopup(spawnedDescription.transform as RectTransform, targetParent as RectTransform);
}
private Transform ResolvePopupParent()
{
if (popupParent != null && popupParent != transform && !popupParent.IsChildOf(transform))
{
return popupParent;
}
Canvas canvas = GetComponentInParent<Canvas>();
return canvas != null ? canvas.transform : transform.parent;
}
private void PositionPopup(RectTransform popupRect, RectTransform parentRect)
{
if (popupRect == null || parentRect == null)
{
return;
}
LayoutRebuilder.ForceRebuildLayoutImmediate(popupRect);
RectTransform itemRect = transform as RectTransform;
if (itemRect == null)
{
popupRect.anchoredPosition = Vector2.zero;
return;
}
Canvas canvas = GetComponentInParent<Canvas>();
Camera localUiCamera = null;
if (canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
{
localUiCamera = canvas.worldCamera;
}
Vector3 worldCenter = itemRect.TransformPoint(itemRect.rect.center);
Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(localUiCamera, worldCenter);
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRect, screenPoint, localUiCamera, out Vector2 localPoint);
float viewportX = localUiCamera != null
? localUiCamera.ScreenToViewportPoint(screenPoint).x
: screenPoint.x / Mathf.Max(1f, Screen.width);
bool placeLeft = viewportX > 0.5f;
float halfItemWidth = itemRect.rect.width * 0.5f;
float halfPopupWidth = popupRect.rect.width * 0.5f;
float xOffset = halfItemWidth + halfPopupWidth + popupHorizontalOffset;
popupRect.anchoredPosition = localPoint + new Vector2(placeLeft ? -xOffset : xOffset, 0f);
}
public void OnBeginDrag(PointerEventData eventData)
{
if (!allowDrag || itemSO == null || eventData == null || eventData.button != PointerEventData.InputButton.Left)
{
isDraggingWithLeftButton = false;
return;
}
isDraggingWithLeftButton = true;
suppressNextClick = true;
SetAllDragTargetsVisible(true);
CreateDragGhost();
UpdateDragGhostPosition(eventData);
}
public void OnDrag(PointerEventData eventData)
{
if (!isDraggingWithLeftButton)
{
return;
}
UpdateDragGhostPosition(eventData);
}
public void OnEndDrag(PointerEventData eventData)
{
if (!isDraggingWithLeftButton)
{
DestroyDragGhost();
SetAllDragTargetsVisible(false);
return;
}
isDraggingWithLeftButton = false;
equipUpdate matchedUpdateTarget = FindMatchingUpdateTarget(eventData);
equipIllusion matchedIllusionTarget = matchedUpdateTarget == null ? FindMatchingIllusionTarget(eventData) : null;
equipSmelt matchedSmeltTarget = matchedUpdateTarget == null && matchedIllusionTarget == null ? FindMatchingSmeltTarget(eventData) : null;
bool cameFromSmeltPool = equipSmelt.IsEquipmentAssignedToSmeltPool(itemSO);
SetAllDragTargetsVisible(false);
DestroyDragGhost();
if (matchedUpdateTarget != null)
{
matchedUpdateTarget.AcceptDraggedEquipment(itemSO);
return;
}
if (matchedIllusionTarget != null)
{
matchedIllusionTarget.AcceptDraggedEquipment(itemSO);
return;
}
if (matchedSmeltTarget != null)
{
matchedSmeltTarget.AcceptDraggedEquipment(itemSO);
return;
}
if (cameFromSmeltPool)
{
equipSmelt.RemoveEquipmentFromSmeltPool(itemSO);
}
}
public void OnPointerClick(PointerEventData eventData)
{
if (!allowQuickTransfer || eventData == null || eventData.button != PointerEventData.InputButton.Right || itemSO == null)
{
return;
}
if (equipSmelt.TryHandleQuickTransfer(itemSO))
{
isDraggingWithLeftButton = false;
SetAllDragTargetsVisible(false);
DestroyDragGhost();
suppressNextClick = true;
}
}
private equipUpdate FindMatchingUpdateTarget(PointerEventData eventData)
{
equipUpdate[] targets = FindObjectsOfType<equipUpdate>(true);
if (targets == null || targets.Length == 0)
{
return null;
}
Vector2 pointerPosition = eventData != null ? eventData.position : Input.mousePosition;
Camera eventCamera = eventData != null && eventData.pressEventCamera != null ? eventData.pressEventCamera : uiCamera;
for (int i = 0; i < targets.Length; i++)
{
equipUpdate target = targets[i];
if (target != null && target.gameObject.activeInHierarchy && target.IsPointerOverDropArea(pointerPosition, eventCamera))
{
return target;
}
}
return null;
}
private equipSmelt FindMatchingSmeltTarget(PointerEventData eventData)
{
equipSmelt[] targets = FindObjectsOfType<equipSmelt>(true);
if (targets == null || targets.Length == 0)
{
return null;
}
Vector2 pointerPosition = eventData != null ? eventData.position : Input.mousePosition;
Camera eventCamera = eventData != null && eventData.pressEventCamera != null ? eventData.pressEventCamera : uiCamera;
for (int i = 0; i < targets.Length; i++)
{
equipSmelt target = targets[i];
if (target != null && target.gameObject.activeInHierarchy && target.IsPointerOverDropArea(pointerPosition, eventCamera))
{
return target;
}
}
return null;
}
private equipIllusion FindMatchingIllusionTarget(PointerEventData eventData)
{
equipIllusion[] targets = FindObjectsOfType<equipIllusion>(true);
if (targets == null || targets.Length == 0)
{
return null;
}
Vector2 pointerPosition = eventData != null ? eventData.position : Input.mousePosition;
Camera eventCamera = eventData != null && eventData.pressEventCamera != null ? eventData.pressEventCamera : uiCamera;
for (int i = 0; i < targets.Length; i++)
{
equipIllusion target = targets[i];
if (target != null && target.gameObject.activeInHierarchy && target.IsPointerOverDropArea(pointerPosition, eventCamera))
{
return target;
}
}
return null;
}
private void CreateDragGhost()
{
DestroyDragGhost();
Transform ghostParent = rootCanvas != null ? rootCanvas.transform : transform.parent;
if (ghostParent == null)
{
return;
}
dragGhost = Instantiate(gameObject, ghostParent);
dragGhost.name = $"{name}_DragGhost";
dragGhost.SetActive(true);
dragGhost.transform.SetAsLastSibling();
dragGhostRect = dragGhost.transform as RectTransform;
if (dragGhostRect != null)
{
dragGhostRect.anchorMin = new Vector2(0.5f, 0.5f);
dragGhostRect.anchorMax = new Vector2(0.5f, 0.5f);
dragGhostRect.pivot = new Vector2(0.5f, 0.5f);
dragGhostRect.localScale = Vector3.one;
dragGhostRect.localRotation = Quaternion.identity;
}
equipItemPrefab ghostItem = dragGhost.GetComponent<equipItemPrefab>();
if (ghostItem != null)
{
ghostItem.enabled = false;
if (ghostItem.itemButton != null)
{
ghostItem.itemButton.interactable = false;
}
}
Button[] buttons = dragGhost.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].interactable = false;
}
Graphic[] graphics = dragGhost.GetComponentsInChildren<Graphic>(true);
for (int i = 0; i < graphics.Length; i++)
{
graphics[i].raycastTarget = false;
}
CanvasGroup canvasGroup = dragGhost.GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
canvasGroup = dragGhost.AddComponent<CanvasGroup>();
}
canvasGroup.alpha = 0.55f;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
}
private void UpdateDragGhostPosition(PointerEventData eventData)
{
if (dragGhostRect == null)
{
return;
}
RectTransform parentRect = dragGhostRect.parent as RectTransform;
if (parentRect == null)
{
return;
}
Vector2 pointerPosition = eventData != null ? eventData.position : (Vector2)Input.mousePosition;
Camera eventCamera = eventData != null && eventData.pressEventCamera != null ? eventData.pressEventCamera : uiCamera;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRect, pointerPosition, eventCamera, out Vector2 localPoint))
{
dragGhostRect.anchoredPosition = localPoint;
}
}
private void DestroyDragGhost()
{
if (dragGhost == null)
{
dragGhostRect = null;
return;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(dragGhost);
}
else
#endif
{
Destroy(dragGhost);
}
dragGhost = null;
dragGhostRect = null;
}
private static void SetAllDragTargetsVisible(bool visible)
{
equipUpdate[] updateTargets = FindObjectsOfType<equipUpdate>(true);
if (updateTargets != null)
{
for (int i = 0; i < updateTargets.Length; i++)
{
if (updateTargets[i] != null && updateTargets[i].gameObject.activeInHierarchy)
{
updateTargets[i].SetDragPreviewVisible(visible);
}
}
}
equipIllusion[] illusionTargets = FindObjectsOfType<equipIllusion>(true);
if (illusionTargets != null)
{
for (int i = 0; i < illusionTargets.Length; i++)
{
if (illusionTargets[i] != null && illusionTargets[i].gameObject.activeInHierarchy)
{
illusionTargets[i].SetDragPreviewVisible(visible);
}
}
}
equipSmelt[] smeltTargets = FindObjectsOfType<equipSmelt>(true);
if (smeltTargets != null)
{
for (int i = 0; i < smeltTargets.Length; i++)
{
if (smeltTargets[i] != null && smeltTargets[i].gameObject.activeInHierarchy)
{
smeltTargets[i].SetDragPreviewVisible(visible);
}
}
}
}
private void ApplyProfileSprite(Sprite sprite)
{
if (itemProfileIcon != null)
{
itemProfileIcon.sprite = sprite;
itemProfileIcon.enabled = sprite != null;
}
}
private void ApplyBottomColor(int colorIndex)
{
if (itemBtm == null)
{
return;
}
Color color = Color.white;
if (itemBtmColors != null && itemBtmColors.Length > 0)
{
int safeIndex = Mathf.Clamp(colorIndex, 0, itemBtmColors.Length - 1);
color = itemBtmColors[safeIndex];
}
itemBtm.color = color;
}
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;
}
public void SetInteractionOptions(bool dragEnabled, bool quickTransferEnabled)
{
allowDrag = dragEnabled;
allowQuickTransfer = quickTransferEnabled;
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: db343678ddc5fd44e971ffbe67d0ba5e
+310
View File
@@ -0,0 +1,310 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &50300314260310283
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4791772059149409634}
- component: {fileID: 6018896216900463250}
- component: {fileID: 8670252801037777817}
- component: {fileID: 2742497410143989620}
- component: {fileID: 6257067395450344725}
m_Layer: 5
m_Name: equipItemPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4791772059149409634
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50300314260310283}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8306989158517587553}
- {fileID: 4501911813970791622}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 120, y: 120}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6018896216900463250
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50300314260310283}
m_CullTransparentMesh: 1
--- !u!114 &8670252801037777817
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50300314260310283}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: db343678ddc5fd44e971ffbe67d0ba5e, type: 3}
m_Name:
m_EditorClassIdentifier:
itemSO: {fileID: 0}
itemBtm: {fileID: 2742497410143989620}
itemBtmColors:
- {r: 0.80784315, g: 0.80784315, b: 0.80784315, a: 1}
- {r: 0.28627452, g: 0.68235296, b: 0.99607843, a: 1}
- {r: 0.5137255, g: 0.3137255, b: 0.9372549, a: 1}
- {r: 1, g: 0.65882355, b: 0.25490198, a: 1}
- {r: 1, g: 0.21960784, b: 0.21960784, a: 1}
- {r: 1, g: 0.40392157, b: 0.6431373, a: 1}
itemProfileIcon: {fileID: 1785277191647662279}
itemType:
itemName:
itemButton: {fileID: 6257067395450344725}
eqpmtDesPrefab: {fileID: 2338382027758302449, guid: 00982b98d18fbe94cb371f5451f6e244, type: 3}
popupParent: {fileID: 0}
popupHorizontalOffset: 120
onItemClicked:
m_PersistentCalls:
m_Calls: []
--- !u!114 &2742497410143989620
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50300314260310283}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.5566038, g: 0.5566038, b: 0.5566038, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &6257067395450344725
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 50300314260310283}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 2742497410143989620}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &5573987670480829073
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8306989158517587553}
- component: {fileID: 141289092566972723}
- component: {fileID: 7835055449099799467}
m_Layer: 5
m_Name: Text (Legacy)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &8306989158517587553
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5573987670480829073}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4791772059149409634}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &141289092566972723
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5573987670480829073}
m_CullTransparentMesh: 1
--- !u!114 &7835055449099799467
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5573987670480829073}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Button
--- !u!1 &7630186706449988748
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4501911813970791622}
- component: {fileID: 2754751966488129414}
- component: {fileID: 1785277191647662279}
m_Layer: 5
m_Name: profile
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4501911813970791622
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7630186706449988748}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4791772059149409634}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 115, y: 115}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2754751966488129414
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7630186706449988748}
m_CullTransparentMesh: 1
--- !u!114 &1785277191647662279
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7630186706449988748}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 58f3bf476bf2f8a44a93e801cd45e726
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5ad32177e0c86fb45b242fba2178163f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
+542
View File
@@ -0,0 +1,542 @@
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "NewEquipmentRandomConfig", menuName = "Equipment/Equipment Random Config")]
public class equipmentRandomConfigSO : ScriptableObject
{
public enum RandomBasicAttributeType
{
MaxHp,
Attack,
MaxMana,
DamageResistance,
ScoreEfficiency
}
public enum RandomSpecialEffectType
{
MaxHp,
Attack,
MaxMana,
DamageResistance,
ScoreEfficiency
}
public enum RandomIllusionEffectType
{
MaxHp,
Attack,
MaxMana,
DamageResistance,
ScoreEfficiency,
HitManaRecovery,
HitDamageMultiplier,
HpLoseBase
}
[Serializable]
public class SpecialEffectRandomRange
{
public RandomSpecialEffectType effectType;
public float minValue;
public float maxValue;
public void Normalize()
{
if (maxValue < minValue)
{
float cached = minValue;
minValue = maxValue;
maxValue = cached;
}
}
}
[Serializable]
public class BasicAttributeRandomRange
{
public RandomBasicAttributeType attributeType;
public float minValue;
public float maxValue;
public void Normalize()
{
if (maxValue < minValue)
{
float cached = minValue;
minValue = maxValue;
maxValue = cached;
}
}
}
[Serializable]
public class IllusionEffectRandomRange
{
public RandomIllusionEffectType effectType;
public float minValue;
public float maxValue;
public void Normalize()
{
if (maxValue < minValue)
{
float cached = minValue;
minValue = maxValue;
maxValue = cached;
}
}
}
[Serializable]
public class SpecialSkillPoolEntry
{
public equipmentSO.EquipmentSkillType skillType;
public List<int> skillIds = new List<int>();
public void Normalize()
{
if (skillIds == null)
{
skillIds = new List<int>();
}
for (int i = 0; i < skillIds.Count; i++)
{
skillIds[i] = Mathf.Max(0, skillIds[i]);
}
}
}
[Header("Random Base Attributes")]
[Min(0)] public int randomBasicAttributeCount = 0;
public List<BasicAttributeRandomRange> basicAttributeRanges = new List<BasicAttributeRandomRange>();
[Header("Special Effect Rules")]
public bool onlyProduceSameTypeAttributes = false;
[Header("Special Effect Count Probabilities")]
[Range(0f, 1f)] public float se01p = 0.6f;
[Range(0f, 1f)] public float se02p = 0.35f;
[Range(0f, 1f)] public float se03p = 0.05f;
[Range(0f, 1f)] public float sesp = 0.03f;
[Header("Illusion Effect Skill Probabilities")]
[Range(0f, 1f)] public float ies01 = 0.2f;
[Range(0f, 1f)] public float ies02 = 0.35f;
[Range(0f, 1f)] public float ies03 = 0.5f;
[Range(0f, 1f)] public float ies04 = 0.65f;
[Header("Special Effect Random Ranges")]
public List<SpecialEffectRandomRange> specialEffectRanges = new List<SpecialEffectRandomRange>();
[Header("Type Same Effect Random Ranges")]
public List<SpecialEffectRandomRange> typeSameEffectRanges = new List<SpecialEffectRandomRange>();
[Header("Illusion Effect Random Ranges")]
public List<IllusionEffectRandomRange> illusionEffectRanges = new List<IllusionEffectRandomRange>();
[Header("Special Skill Pool")]
public List<SpecialSkillPoolEntry> specialSkillPool = new List<SpecialSkillPoolEntry>();
[Header("Illusion Skill Pool")]
public List<int> illusionSkillPool = new List<int>();
private void OnValidate()
{
NormalizeRuntimeData();
}
public void NormalizeRuntimeData()
{
randomBasicAttributeCount = Mathf.Max(0, randomBasicAttributeCount);
se01p = Mathf.Clamp01(se01p);
se02p = Mathf.Clamp01(se02p);
se03p = Mathf.Clamp01(se03p);
sesp = Mathf.Clamp01(sesp);
ies01 = Mathf.Clamp01(ies01);
ies02 = Mathf.Clamp01(ies02);
ies03 = Mathf.Clamp01(ies03);
ies04 = Mathf.Clamp01(ies04);
EnsureBasicAttributeRanges();
EnsureSpecialEffectRanges();
EnsureTypeSameEffectRanges();
EnsureIllusionEffectRanges();
EnsureSpecialSkillPool();
NormalizeIllusionSkillPool();
}
public bool TryGetSpecialRange(RandomSpecialEffectType effectType, out float minValue, out float maxValue)
{
SpecialEffectRandomRange range = FindSpecialRange(effectType);
if (range != null)
{
minValue = range.minValue;
maxValue = range.maxValue;
return true;
}
minValue = 0f;
maxValue = 0f;
return false;
}
public bool TryGetTypeSameEffectRange(RandomSpecialEffectType effectType, out float minValue, out float maxValue)
{
SpecialEffectRandomRange range = FindTypeSameEffectRange(effectType);
if (range != null)
{
minValue = range.minValue;
maxValue = range.maxValue;
return true;
}
minValue = 0f;
maxValue = 0f;
return false;
}
public bool TryGetBasicRange(RandomBasicAttributeType attributeType, out float minValue, out float maxValue)
{
BasicAttributeRandomRange range = FindBasicRange(attributeType);
if (range != null)
{
minValue = range.minValue;
maxValue = range.maxValue;
return true;
}
minValue = 0f;
maxValue = 0f;
return false;
}
public bool TryGetIllusionRange(RandomIllusionEffectType effectType, out float minValue, out float maxValue)
{
IllusionEffectRandomRange range = FindIllusionRange(effectType);
if (range != null)
{
minValue = range.minValue;
maxValue = range.maxValue;
return true;
}
minValue = 0f;
maxValue = 0f;
return false;
}
public bool TryGetIllusionEffectRange(RandomIllusionEffectType effectType, out float minValue, out float maxValue)
{
return TryGetIllusionRange(effectType, out minValue, out maxValue);
}
public bool TryGetIllusionEffectRange(equipmentSO.EquipmentSpecialEffectType effectType, out float minValue, out float maxValue)
{
if (TryMapToIllusionEffectType(effectType, out RandomIllusionEffectType mappedType))
{
return TryGetIllusionRange(mappedType, out minValue, out maxValue);
}
minValue = 0f;
maxValue = 0f;
return false;
}
public bool TryGetSpecialSkillId(equipmentSO.EquipmentSkillType skillType, out int skillId)
{
NormalizeRuntimeData();
for (int i = 0; i < specialSkillPool.Count; i++)
{
SpecialSkillPoolEntry entry = specialSkillPool[i];
if (entry != null && entry.skillType == skillType && entry.skillIds != null && entry.skillIds.Count > 0)
{
skillId = entry.skillIds[UnityEngine.Random.Range(0, entry.skillIds.Count)];
return true;
}
}
skillId = 0;
return false;
}
public bool TryGetIllusionSkillId(out int skillId)
{
NormalizeRuntimeData();
if (illusionSkillPool == null || illusionSkillPool.Count == 0)
{
skillId = 0;
return false;
}
var validIds = new List<int>();
for (int i = 0; i < illusionSkillPool.Count; i++)
{
if (illusionSkillPool[i] > 0)
{
validIds.Add(illusionSkillPool[i]);
}
}
if (validIds.Count == 0)
{
skillId = 0;
return false;
}
skillId = validIds[UnityEngine.Random.Range(0, validIds.Count)];
return true;
}
private static bool TryMapToIllusionEffectType(equipmentSO.EquipmentSpecialEffectType effectType, out RandomIllusionEffectType mappedType)
{
switch (effectType)
{
case equipmentSO.EquipmentSpecialEffectType.MaxHp:
mappedType = RandomIllusionEffectType.MaxHp;
return true;
case equipmentSO.EquipmentSpecialEffectType.Attack:
mappedType = RandomIllusionEffectType.Attack;
return true;
case equipmentSO.EquipmentSpecialEffectType.MaxMana:
mappedType = RandomIllusionEffectType.MaxMana;
return true;
case equipmentSO.EquipmentSpecialEffectType.DamageResistance:
mappedType = RandomIllusionEffectType.DamageResistance;
return true;
case equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency:
mappedType = RandomIllusionEffectType.ScoreEfficiency;
return true;
case equipmentSO.EquipmentSpecialEffectType.HitManaRecovery:
mappedType = RandomIllusionEffectType.HitManaRecovery;
return true;
case equipmentSO.EquipmentSpecialEffectType.HitDamageMultiplier:
mappedType = RandomIllusionEffectType.HitDamageMultiplier;
return true;
case equipmentSO.EquipmentSpecialEffectType.HpLoseBase:
mappedType = RandomIllusionEffectType.HpLoseBase;
return true;
default:
mappedType = default;
return false;
}
}
private void EnsureBasicAttributeRanges()
{
if (basicAttributeRanges == null)
{
basicAttributeRanges = new List<BasicAttributeRandomRange>();
}
var normalized = new List<BasicAttributeRandomRange>();
Array attributeTypes = Enum.GetValues(typeof(RandomBasicAttributeType));
for (int i = 0; i < attributeTypes.Length; i++)
{
RandomBasicAttributeType attributeType = (RandomBasicAttributeType)attributeTypes.GetValue(i);
BasicAttributeRandomRange existing = FindBasicRange(attributeType);
if (existing == null)
{
existing = new BasicAttributeRandomRange { attributeType = attributeType };
}
existing.attributeType = attributeType;
existing.Normalize();
normalized.Add(existing);
}
basicAttributeRanges = normalized;
}
private void EnsureSpecialEffectRanges()
{
if (specialEffectRanges == null)
{
specialEffectRanges = new List<SpecialEffectRandomRange>();
}
var normalized = new List<SpecialEffectRandomRange>();
Array effectTypes = Enum.GetValues(typeof(RandomSpecialEffectType));
for (int i = 0; i < effectTypes.Length; i++)
{
RandomSpecialEffectType effectType = (RandomSpecialEffectType)effectTypes.GetValue(i);
SpecialEffectRandomRange existing = FindSpecialRange(effectType);
if (existing == null)
{
existing = new SpecialEffectRandomRange { effectType = effectType };
}
existing.effectType = effectType;
existing.Normalize();
normalized.Add(existing);
}
specialEffectRanges = normalized;
}
private void EnsureTypeSameEffectRanges()
{
if (typeSameEffectRanges == null)
{
typeSameEffectRanges = new List<SpecialEffectRandomRange>();
}
var normalized = new List<SpecialEffectRandomRange>();
Array effectTypes = Enum.GetValues(typeof(RandomSpecialEffectType));
for (int i = 0; i < effectTypes.Length; i++)
{
RandomSpecialEffectType effectType = (RandomSpecialEffectType)effectTypes.GetValue(i);
SpecialEffectRandomRange existing = FindTypeSameEffectRange(effectType);
if (existing == null)
{
existing = new SpecialEffectRandomRange { effectType = effectType };
}
existing.effectType = effectType;
existing.Normalize();
normalized.Add(existing);
}
typeSameEffectRanges = normalized;
}
private void EnsureIllusionEffectRanges()
{
if (illusionEffectRanges == null)
{
illusionEffectRanges = new List<IllusionEffectRandomRange>();
}
var normalized = new List<IllusionEffectRandomRange>();
Array effectTypes = Enum.GetValues(typeof(RandomIllusionEffectType));
for (int i = 0; i < effectTypes.Length; i++)
{
RandomIllusionEffectType effectType = (RandomIllusionEffectType)effectTypes.GetValue(i);
IllusionEffectRandomRange existing = FindIllusionRange(effectType);
if (existing == null)
{
existing = new IllusionEffectRandomRange { effectType = effectType };
}
existing.effectType = effectType;
existing.Normalize();
normalized.Add(existing);
}
illusionEffectRanges = normalized;
}
private void EnsureSpecialSkillPool()
{
if (specialSkillPool == null)
{
specialSkillPool = new List<SpecialSkillPoolEntry>();
}
var normalized = new List<SpecialSkillPoolEntry>();
Array skillTypes = Enum.GetValues(typeof(equipmentSO.EquipmentSkillType));
for (int i = 0; i < skillTypes.Length; i++)
{
equipmentSO.EquipmentSkillType skillType = (equipmentSO.EquipmentSkillType)skillTypes.GetValue(i);
SpecialSkillPoolEntry existing = FindSpecialSkillPoolEntry(skillType);
if (existing == null)
{
existing = new SpecialSkillPoolEntry { skillType = skillType };
}
existing.skillType = skillType;
existing.Normalize();
normalized.Add(existing);
}
specialSkillPool = normalized;
}
private void NormalizeIllusionSkillPool()
{
if (illusionSkillPool == null)
{
illusionSkillPool = new List<int>();
return;
}
for (int i = 0; i < illusionSkillPool.Count; i++)
{
illusionSkillPool[i] = Mathf.Max(0, illusionSkillPool[i]);
}
}
private SpecialEffectRandomRange FindSpecialRange(RandomSpecialEffectType effectType)
{
for (int i = 0; i < specialEffectRanges.Count; i++)
{
SpecialEffectRandomRange range = specialEffectRanges[i];
if (range != null && range.effectType == effectType)
{
return range;
}
}
return null;
}
private BasicAttributeRandomRange FindBasicRange(RandomBasicAttributeType attributeType)
{
for (int i = 0; i < basicAttributeRanges.Count; i++)
{
BasicAttributeRandomRange range = basicAttributeRanges[i];
if (range != null && range.attributeType == attributeType)
{
return range;
}
}
return null;
}
private SpecialEffectRandomRange FindTypeSameEffectRange(RandomSpecialEffectType effectType)
{
for (int i = 0; i < typeSameEffectRanges.Count; i++)
{
SpecialEffectRandomRange range = typeSameEffectRanges[i];
if (range != null && range.effectType == effectType)
{
return range;
}
}
return null;
}
private IllusionEffectRandomRange FindIllusionRange(RandomIllusionEffectType effectType)
{
for (int i = 0; i < illusionEffectRanges.Count; i++)
{
IllusionEffectRandomRange range = illusionEffectRanges[i];
if (range != null && range.effectType == effectType)
{
return range;
}
}
return null;
}
private SpecialSkillPoolEntry FindSpecialSkillPoolEntry(equipmentSO.EquipmentSkillType skillType)
{
for (int i = 0; i < specialSkillPool.Count; i++)
{
SpecialSkillPoolEntry entry = specialSkillPool[i];
if (entry != null && entry.skillType == skillType)
{
return entry;
}
}
return null;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fbec1eb650c88494083b6b5e079cc4a2
@@ -0,0 +1,910 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEditorInternal;
#endif
public class equipmentRandomTestButton : MonoBehaviour
{
private const string EditorOutputFolder = "Assets/Resources/so/uEquip";
[Serializable]
public class GeneratedStatValue
{
public string statName;
public float value;
}
[Serializable]
public class GeneratedEffectValue
{
public equipmentSO.EquipmentSpecialEffectType effectType;
public string displayName;
public float value;
public Sprite displayIcon;
public int skillId;
}
[Header("Source")]
public equipmentRandomConfigSO randomConfig;
public equipmentSO sourceEquipment;
public bool saveGeneratedAssetInEditor = true;
public equipBag targetEquipBag;
[Header("Generated Preview")]
public equipmentSO lastGeneratedEquipment;
public List<GeneratedStatValue> generatedBasicAttributes = new List<GeneratedStatValue>();
public List<GeneratedEffectValue> generatedTypeSameEffects = new List<GeneratedEffectValue>();
public List<GeneratedEffectValue> generatedSpecialEffects = new List<GeneratedEffectValue>();
public List<GeneratedEffectValue> generatedIllusionEffects = new List<GeneratedEffectValue>();
[TextArea(4, 12)]
public string lastGenerationSummary;
public string lastGeneratedAssetPath;
[ContextMenu("Generate Equipment Preview")]
public void GenerateEquipmentPreview()
{
GenerateEquipmentSO();
}
[ContextMenu("Refresh Equipment List")]
public void RefreshEquipmentList()
{
if (targetEquipBag != null)
{
targetEquipBag.Rebuild();
}
}
[ContextMenu("Generate Equipment SO")]
public void GenerateEquipmentSO()
{
generatedBasicAttributes.Clear();
generatedTypeSameEffects.Clear();
generatedSpecialEffects.Clear();
generatedIllusionEffects.Clear();
lastGenerationSummary = string.Empty;
lastGeneratedEquipment = null;
lastGeneratedAssetPath = string.Empty;
Debug.Log("[equipmentRandomTestButton] GenerateEquipmentSO invoked.", this);
if (randomConfig == null || sourceEquipment == null)
{
lastGenerationSummary = "Missing randomConfig or sourceEquipment.";
Debug.LogWarning("[equipmentRandomTestButton] Missing randomConfig or sourceEquipment.");
return;
}
randomConfig.NormalizeRuntimeData();
#if UNITY_EDITOR
if (!Application.isPlaying)
{
EditorUtility.SetDirty(randomConfig);
}
#endif
equipmentSO generated = Instantiate(sourceEquipment);
generated.name = BuildGeneratedName(sourceEquipment);
generated.hideFlags = HideFlags.None;
generated.level = 0;
generated.sa_skillID = 0;
generated.ia_skillID = 0;
generated.enableTypeSameEffects = sourceEquipment != null && sourceEquipment.enableTypeSameEffects;
generated.typeSameEffects = Array.Empty<equipmentSO.EquipmentSpecialEffect>();
ResetBasicGains(generated);
GenerateBasicAttributes(generated);
GenerateTypeSameEffects(generated);
GenerateSpecialEffects(generated);
GenerateIllusionEffects(generated);
lastGeneratedEquipment = PersistGeneratedEquipment(generated);
BuildSummary(generated);
RefreshEquipmentList();
MarkHostDirty();
}
private void GenerateBasicAttributes(equipmentSO generated)
{
if (generated == null)
{
return;
}
var candidates = new List<(string name, equipmentSO.EquipmentStatTuning tuning, equipmentRandomConfigSO.RandomBasicAttributeType type)>
{
("MaxHp", generated.maxHp, equipmentRandomConfigSO.RandomBasicAttributeType.MaxHp),
("Attack", generated.attack, equipmentRandomConfigSO.RandomBasicAttributeType.Attack),
("MaxMana", generated.maxMana, equipmentRandomConfigSO.RandomBasicAttributeType.MaxMana),
("DamageResistance", generated.damageResistance, equipmentRandomConfigSO.RandomBasicAttributeType.DamageResistance),
("ScoreEfficiency", generated.scoreEfficiency, equipmentRandomConfigSO.RandomBasicAttributeType.ScoreEfficiency)
};
candidates.RemoveAll(entry =>
entry.tuning == null ||
!randomConfig.TryGetBasicRange(entry.type, out _, out _));
int count = Mathf.Clamp(randomConfig.randomBasicAttributeCount, 0, candidates.Count);
for (int i = 0; i < count; i++)
{
int pickIndex = UnityEngine.Random.Range(0, candidates.Count);
var picked = candidates[pickIndex];
candidates.RemoveAt(pickIndex);
randomConfig.TryGetBasicRange(picked.type, out float minValue, out float maxValue);
float rolledValue = RollBiasedValue(minValue, maxValue);
picked.tuning.basicGain = rolledValue;
generatedBasicAttributes.Add(new GeneratedStatValue
{
statName = picked.name,
value = rolledValue
});
}
MarkEquipmentDirty(generated);
}
private void GenerateSpecialEffects(equipmentSO generated)
{
if (generated == null)
{
return;
}
int effectCount = RollSpecialEffectCount();
if (effectCount <= 0)
{
return;
}
HashSet<equipmentSO.EquipmentSpecialEffectType> selectedBasicTypes = GetSelectedBasicAttributeTypes(generated);
List<equipmentSO.EquipmentSpecialEffectType> valuePool = BuildSpecialEffectPool(selectedBasicTypes, generated.enableTypeSameEffects);
if (valuePool.Count == 0)
{
generated.specialEffects = Array.Empty<equipmentSO.EquipmentSpecialEffect>();
generated.sa_skillID = 0;
MarkEquipmentDirty(generated);
return;
}
for (int i = 0; i < effectCount; i++)
{
int pickIndex = UnityEngine.Random.Range(0, valuePool.Count);
equipmentSO.EquipmentSpecialEffectType effectType = valuePool[pickIndex];
if (!TryMapToSpecialRange(effectType, out equipmentRandomConfigSO.RandomSpecialEffectType rangeType))
{
continue;
}
if (!randomConfig.TryGetSpecialRange(rangeType, out float minValue, out float maxValue))
{
continue;
}
generatedSpecialEffects.Add(new GeneratedEffectValue
{
effectType = effectType,
displayName = effectType.ToString(),
value = RollBiasedValue(minValue, maxValue),
displayIcon = null,
skillId = 0
});
}
ResolveDuplicateEffects(generatedSpecialEffects);
TryGenerateSpecialSkill(generated);
generated.specialEffects = BuildGeneratedEffectArray(generatedSpecialEffects);
MarkEquipmentDirty(generated);
}
private void GenerateTypeSameEffects(equipmentSO generated)
{
if (generated == null)
{
return;
}
generated.typeSameEffects = Array.Empty<equipmentSO.EquipmentSpecialEffect>();
HashSet<equipmentSO.EquipmentSpecialEffectType> selectedBasicTypes = GetSelectedBasicAttributeTypes(generated);
if (selectedBasicTypes.Count == 0)
{
return;
}
var generatedEffects = new List<equipmentSO.EquipmentSpecialEffect>();
foreach (equipmentSO.EquipmentSpecialEffectType effectType in selectedBasicTypes)
{
if (!TryMapToSpecialRange(effectType, out equipmentRandomConfigSO.RandomSpecialEffectType rangeType))
{
continue;
}
if (!randomConfig.TryGetTypeSameEffectRange(rangeType, out float minValue, out float maxValue))
{
continue;
}
float rolledValue = RollBiasedValue(minValue, maxValue);
generatedEffects.Add(new equipmentSO.EquipmentSpecialEffect
{
effectType = effectType,
value = rolledValue
});
generatedTypeSameEffects.Add(new GeneratedEffectValue
{
effectType = effectType,
displayName = effectType.ToString(),
value = rolledValue,
displayIcon = null,
skillId = 0
});
}
generated.typeSameEffects = generatedEffects.ToArray();
MarkEquipmentDirty(generated);
}
private void TryGenerateSpecialSkill(equipmentSO generated)
{
if (generated == null || generatedSpecialEffects.Count == 0)
{
generated.sa_skillID = 0;
return;
}
if (UnityEngine.Random.value > randomConfig.sesp)
{
generated.sa_skillID = 0;
return;
}
if (!randomConfig.TryGetSpecialSkillId(generated.skillType, out int skillId) || skillId <= 0)
{
generated.sa_skillID = 0;
return;
}
int replaceIndex = UnityEngine.Random.Range(0, generatedSpecialEffects.Count);
generatedSpecialEffects.RemoveAt(replaceIndex);
generatedSpecialEffects.Add(new GeneratedEffectValue
{
effectType = equipmentSO.EquipmentSpecialEffectType.Skill,
displayName = "Skill",
value = 0f,
displayIcon = null,
skillId = skillId
});
generated.sa_skillID = skillId;
}
private List<equipmentSO.EquipmentSpecialEffectType> BuildSpecialEffectPool(
HashSet<equipmentSO.EquipmentSpecialEffectType> selectedBasicTypes,
bool alignToSelectedBasicTypes)
{
var pool = new List<equipmentSO.EquipmentSpecialEffectType>();
if (alignToSelectedBasicTypes && selectedBasicTypes != null && selectedBasicTypes.Count > 0)
{
foreach (equipmentSO.EquipmentSpecialEffectType effectType in selectedBasicTypes)
{
if (!TryMapToSpecialRange(effectType, out equipmentRandomConfigSO.RandomSpecialEffectType rangeType))
{
continue;
}
if (randomConfig.TryGetSpecialRange(rangeType, out _, out _))
{
pool.Add(effectType);
}
}
return pool;
}
equipmentSO.EquipmentSpecialEffectType[] allTypes =
{
equipmentSO.EquipmentSpecialEffectType.MaxHp,
equipmentSO.EquipmentSpecialEffectType.Attack,
equipmentSO.EquipmentSpecialEffectType.MaxMana,
equipmentSO.EquipmentSpecialEffectType.DamageResistance,
equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency
};
for (int i = 0; i < allTypes.Length; i++)
{
if (!TryMapToSpecialRange(allTypes[i], out equipmentRandomConfigSO.RandomSpecialEffectType rangeType))
{
continue;
}
if (randomConfig.TryGetSpecialRange(rangeType, out _, out _))
{
pool.Add(allTypes[i]);
}
}
return pool;
}
private void GenerateIllusionEffects(equipmentSO generated)
{
if (generated == null || generated.illusionEffects == null || generated.illusionEffects.Length == 0)
{
return;
}
generated.ia_skillID = 0;
int effectCount = Mathf.Min(RollSpecialEffectCount(), generated.illusionEffects.Length);
List<equipmentSO.EquipmentSpecialEffect> skillPool = new List<equipmentSO.EquipmentSpecialEffect>();
List<equipmentSO.EquipmentSpecialEffect> valuePool = new List<equipmentSO.EquipmentSpecialEffect>();
for (int i = 0; i < generated.illusionEffects.Length; i++)
{
equipmentSO.EquipmentSpecialEffect effect = generated.illusionEffects[i];
if (effect == null)
{
continue;
}
if (effect.effectType == equipmentSO.EquipmentSpecialEffectType.Skill)
{
skillPool.Add(effect);
}
else if (TryMapToIllusionRange(effect.effectType, out _))
{
valuePool.Add(effect);
}
}
for (int slotIndex = 0; slotIndex < effectCount; slotIndex++)
{
bool shouldGenerateSkill = skillPool.Count > 0 && UnityEngine.Random.value <= GetIllusionSkillChance(slotIndex);
if (shouldGenerateSkill)
{
if (!randomConfig.TryGetIllusionSkillId(out int illusionSkillId) || illusionSkillId <= 0)
{
shouldGenerateSkill = false;
}
else
{
int pickSkillIndex = UnityEngine.Random.Range(0, skillPool.Count);
equipmentSO.EquipmentSpecialEffect skillEffect = skillPool[pickSkillIndex];
skillPool.RemoveAt(pickSkillIndex);
generatedIllusionEffects.Add(new GeneratedEffectValue
{
effectType = skillEffect.effectType,
displayName = "Skill",
value = 0f,
displayIcon = null,
skillId = illusionSkillId
});
generated.ia_skillID = illusionSkillId;
continue;
}
}
if (valuePool.Count == 0)
{
break;
}
int pickValueIndex = UnityEngine.Random.Range(0, valuePool.Count);
equipmentSO.EquipmentSpecialEffect effect = valuePool[pickValueIndex];
valuePool.RemoveAt(pickValueIndex);
if (!TryMapToIllusionRange(effect.effectType, out equipmentRandomConfigSO.RandomIllusionEffectType rangeType))
{
slotIndex--;
continue;
}
if (!randomConfig.TryGetIllusionRange(rangeType, out float minValue, out float maxValue))
{
slotIndex--;
continue;
}
generatedIllusionEffects.Add(new GeneratedEffectValue
{
effectType = effect.effectType,
displayName = effect.effectType.ToString(),
value = RollBiasedValue(minValue, maxValue),
displayIcon = null,
skillId = 0
});
}
generated.illusionEffects = BuildGeneratedEffectArray(generatedIllusionEffects);
MarkEquipmentDirty(generated);
}
private int RollSpecialEffectCount()
{
float roll = UnityEngine.Random.value;
if (roll <= randomConfig.se01p)
{
return 1;
}
if (roll <= randomConfig.se01p + randomConfig.se02p)
{
return 2;
}
return 3;
}
private float GetIllusionSkillChance(int index)
{
switch (index)
{
case 0: return randomConfig.ies01;
case 1: return randomConfig.ies02;
case 2: return randomConfig.ies03;
case 3: return randomConfig.ies04;
default: return 0f;
}
}
private static bool TryMapToSpecialRange(
equipmentSO.EquipmentSpecialEffectType effectType,
out equipmentRandomConfigSO.RandomSpecialEffectType rangeType)
{
switch (effectType)
{
case equipmentSO.EquipmentSpecialEffectType.MaxHp:
rangeType = equipmentRandomConfigSO.RandomSpecialEffectType.MaxHp;
return true;
case equipmentSO.EquipmentSpecialEffectType.Attack:
rangeType = equipmentRandomConfigSO.RandomSpecialEffectType.Attack;
return true;
case equipmentSO.EquipmentSpecialEffectType.MaxMana:
rangeType = equipmentRandomConfigSO.RandomSpecialEffectType.MaxMana;
return true;
case equipmentSO.EquipmentSpecialEffectType.DamageResistance:
rangeType = equipmentRandomConfigSO.RandomSpecialEffectType.DamageResistance;
return true;
case equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency:
rangeType = equipmentRandomConfigSO.RandomSpecialEffectType.ScoreEfficiency;
return true;
default:
rangeType = default;
return false;
}
}
private static bool TryMapToIllusionRange(
equipmentSO.EquipmentSpecialEffectType effectType,
out equipmentRandomConfigSO.RandomIllusionEffectType rangeType)
{
switch (effectType)
{
case equipmentSO.EquipmentSpecialEffectType.MaxHp:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.MaxHp;
return true;
case equipmentSO.EquipmentSpecialEffectType.Attack:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.Attack;
return true;
case equipmentSO.EquipmentSpecialEffectType.MaxMana:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.MaxMana;
return true;
case equipmentSO.EquipmentSpecialEffectType.DamageResistance:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.DamageResistance;
return true;
case equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.ScoreEfficiency;
return true;
case equipmentSO.EquipmentSpecialEffectType.HitManaRecovery:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.HitManaRecovery;
return true;
case equipmentSO.EquipmentSpecialEffectType.HitDamageMultiplier:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.HitDamageMultiplier;
return true;
case equipmentSO.EquipmentSpecialEffectType.HpLoseBase:
rangeType = equipmentRandomConfigSO.RandomIllusionEffectType.HpLoseBase;
return true;
default:
rangeType = default;
return false;
}
}
private void BuildSummary(equipmentSO generated)
{
StringBuilder builder = new StringBuilder();
builder.AppendLine("Basic Attributes:");
for (int i = 0; i < generatedBasicAttributes.Count; i++)
{
builder.AppendLine($"- {generatedBasicAttributes[i].statName}: {generatedBasicAttributes[i].value:0.####}");
}
builder.AppendLine("Special Effects:");
for (int i = 0; i < generatedSpecialEffects.Count; i++)
{
GeneratedEffectValue effect = generatedSpecialEffects[i];
if (effect.effectType == equipmentSO.EquipmentSpecialEffectType.Skill)
{
builder.AppendLine($"- Skill: {effect.skillId}");
}
else
{
builder.AppendLine($"- {effect.effectType}: {effect.value:0.####}");
}
}
builder.AppendLine("Type Same Effects:");
for (int i = 0; i < generatedTypeSameEffects.Count; i++)
{
GeneratedEffectValue effect = generatedTypeSameEffects[i];
builder.AppendLine($"- {effect.effectType}: {effect.value:0.####}");
}
builder.AppendLine("Illusion Effects:");
for (int i = 0; i < generatedIllusionEffects.Count; i++)
{
GeneratedEffectValue effect = generatedIllusionEffects[i];
if (effect.effectType == equipmentSO.EquipmentSpecialEffectType.Skill)
{
builder.AppendLine($"- Skill");
}
else
{
builder.AppendLine($"- {effect.effectType}: {effect.value:0.####}");
}
}
if (generated != null && generated.sa_skillID > 0)
{
builder.AppendLine($"sa_skillID: {generated.sa_skillID}");
}
if (generatedBasicAttributes.Count == 0 && generatedTypeSameEffects.Count == 0 && generatedSpecialEffects.Count == 0 && generatedIllusionEffects.Count == 0)
{
builder.AppendLine();
builder.AppendLine("No values generated.");
builder.AppendLine($"randomBasicAttributeCount={randomConfig.randomBasicAttributeCount}");
builder.AppendLine($"basicAttributeRangesDefined={(randomConfig.basicAttributeRanges == null ? 0 : randomConfig.basicAttributeRanges.Count)}");
builder.AppendLine($"specialEffectsDefined={(sourceEquipment.specialEffects == null ? 0 : sourceEquipment.specialEffects.Length)}");
builder.AppendLine($"illusionEffectsDefined={(sourceEquipment.illusionEffects == null ? 0 : sourceEquipment.illusionEffects.Length)}");
}
lastGenerationSummary = builder.ToString().TrimEnd();
Debug.Log("[equipmentRandomTestButton] Generated equipment preview:\n" + lastGenerationSummary, this);
}
private void ResetBasicGains(equipmentSO targetEquipment)
{
if (targetEquipment == null)
{
return;
}
if (targetEquipment.maxHp != null) targetEquipment.maxHp.basicGain = 0f;
if (targetEquipment.attack != null) targetEquipment.attack.basicGain = 0f;
if (targetEquipment.maxMana != null) targetEquipment.maxMana.basicGain = 0f;
if (targetEquipment.damageResistance != null) targetEquipment.damageResistance.basicGain = 0f;
if (targetEquipment.scoreEfficiency != null) targetEquipment.scoreEfficiency.basicGain = 0f;
}
private void MarkEquipmentDirty(equipmentSO targetEquipment)
{
#if UNITY_EDITOR
if (!Application.isPlaying && targetEquipment != null)
{
EditorUtility.SetDirty(targetEquipment);
AssetDatabase.SaveAssets();
}
#endif
}
private equipmentSO PersistGeneratedEquipment(equipmentSO generated)
{
if (generated == null)
{
return null;
}
#if UNITY_EDITOR
if (saveGeneratedAssetInEditor)
{
EnsureEditorOutputFolderExists();
string assetPath = AssetDatabase.GenerateUniqueAssetPath($"{EditorOutputFolder}/{generated.name}.asset");
AssetDatabase.CreateAsset(generated, assetPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
lastGeneratedAssetPath = assetPath;
return AssetDatabase.LoadAssetAtPath<equipmentSO>(assetPath);
}
#endif
return generated;
}
private static string BuildGeneratedName(equipmentSO source)
{
int typeIndex = source != null ? (int)source.skillType : 0;
int nextId = GetNextGeneratedId();
return $"type{typeIndex}_{DateTime.Now:yyyyMMdd}_{nextId:00000000}";
}
private static int GetNextGeneratedId()
{
#if UNITY_EDITOR
string absoluteFolder = Path.Combine(Directory.GetCurrentDirectory(), "Assets", "Resources", "so", "uEquip");
if (!Directory.Exists(absoluteFolder))
{
return 1;
}
int maxId = 0;
string[] files = Directory.GetFiles(absoluteFolder, "*.asset", SearchOption.TopDirectoryOnly);
for (int i = 0; i < files.Length; i++)
{
string fileName = Path.GetFileNameWithoutExtension(files[i]);
if (string.IsNullOrWhiteSpace(fileName))
{
continue;
}
int lastUnderscore = fileName.LastIndexOf('_');
if (lastUnderscore < 0 || lastUnderscore >= fileName.Length - 1)
{
continue;
}
string idPart = fileName.Substring(lastUnderscore + 1);
if (int.TryParse(idPart, out int parsedId) && parsedId > maxId)
{
maxId = parsedId;
}
}
return maxId + 1;
#else
return 1;
#endif
}
private static void WriteGeneratedEffectsBack(
equipmentSO.EquipmentSpecialEffect[] targetEffects,
List<GeneratedEffectValue> generatedEffects)
{
if (targetEffects == null)
{
return;
}
for (int i = 0; i < targetEffects.Length; i++)
{
equipmentSO.EquipmentSpecialEffect target = targetEffects[i];
if (target == null)
{
continue;
}
target.value = 0f;
}
for (int i = 0; i < generatedEffects.Count; i++)
{
GeneratedEffectValue generated = generatedEffects[i];
if (generated.effectType == equipmentSO.EquipmentSpecialEffectType.Skill)
{
continue;
}
for (int j = 0; j < targetEffects.Length; j++)
{
equipmentSO.EquipmentSpecialEffect target = targetEffects[j];
if (target == null)
{
continue;
}
if (target.effectType == generated.effectType)
{
target.value = generated.value;
break;
}
}
}
}
private static equipmentSO.EquipmentSpecialEffect[] BuildGeneratedEffectArray(List<GeneratedEffectValue> generatedEffects)
{
if (generatedEffects == null || generatedEffects.Count == 0)
{
return Array.Empty<equipmentSO.EquipmentSpecialEffect>();
}
var results = new List<equipmentSO.EquipmentSpecialEffect>(generatedEffects.Count);
for (int i = 0; i < generatedEffects.Count; i++)
{
GeneratedEffectValue generated = generatedEffects[i];
results.Add(new equipmentSO.EquipmentSpecialEffect
{
effectType = generated.effectType,
value = generated.effectType == equipmentSO.EquipmentSpecialEffectType.Skill ? 0f : generated.value
});
}
return results.ToArray();
}
private HashSet<equipmentSO.EquipmentSpecialEffectType> GetSelectedBasicAttributeTypes(equipmentSO targetEquipment)
{
var selected = new HashSet<equipmentSO.EquipmentSpecialEffectType>();
if (targetEquipment == null)
{
return selected;
}
if (targetEquipment.maxHp != null && !Mathf.Approximately(targetEquipment.maxHp.basicGain, 0f))
selected.Add(equipmentSO.EquipmentSpecialEffectType.MaxHp);
if (targetEquipment.attack != null && !Mathf.Approximately(targetEquipment.attack.basicGain, 0f))
selected.Add(equipmentSO.EquipmentSpecialEffectType.Attack);
if (targetEquipment.maxMana != null && !Mathf.Approximately(targetEquipment.maxMana.basicGain, 0f))
selected.Add(equipmentSO.EquipmentSpecialEffectType.MaxMana);
if (targetEquipment.damageResistance != null && !Mathf.Approximately(targetEquipment.damageResistance.basicGain, 0f))
selected.Add(equipmentSO.EquipmentSpecialEffectType.DamageResistance);
if (targetEquipment.scoreEfficiency != null && !Mathf.Approximately(targetEquipment.scoreEfficiency.basicGain, 0f))
selected.Add(equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency);
return selected;
}
#if UNITY_EDITOR
private static void EnsureEditorOutputFolderExists()
{
if (AssetDatabase.IsValidFolder(EditorOutputFolder))
{
return;
}
if (!AssetDatabase.IsValidFolder("Assets/Resources"))
{
AssetDatabase.CreateFolder("Assets", "Resources");
}
if (!AssetDatabase.IsValidFolder("Assets/Resources/so"))
{
AssetDatabase.CreateFolder("Assets/Resources", "so");
}
if (!AssetDatabase.IsValidFolder(EditorOutputFolder))
{
AssetDatabase.CreateFolder("Assets/Resources/so", "uEquip");
}
}
#endif
private void MarkHostDirty()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
EditorUtility.SetDirty(this);
if (gameObject != null && gameObject.scene.IsValid())
{
EditorSceneManager.MarkSceneDirty(gameObject.scene);
}
InternalEditorUtility.RepaintAllViews();
}
#endif
}
private static float RollBiasedValue(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 span = maxValue - minValue;
float roll = UnityEngine.Random.value;
if (roll <= 0.05f)
{
return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(minValue, minValue + span * 0.1f));
}
if (roll >= 0.95f)
{
return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(maxValue - span * 0.1f, maxValue));
}
float gaussian = SampleClampedGaussian01();
return AvoidZero(minValue, maxValue, Mathf.Lerp(minValue, maxValue, gaussian));
}
private static float SampleClampedGaussian01()
{
float u1 = Mathf.Clamp01(UnityEngine.Random.value);
float u2 = Mathf.Clamp01(UnityEngine.Random.value);
u1 = Mathf.Max(u1, 1e-6f);
float standardNormal = Mathf.Sqrt(-2f * Mathf.Log(u1)) * Mathf.Cos(2f * Mathf.PI * u2);
float centered = 0.5f + standardNormal * 0.18f;
return Mathf.Clamp01(centered);
}
private static void ResolveDuplicateEffects(List<GeneratedEffectValue> effects)
{
if (effects == null || effects.Count <= 1)
{
return;
}
var bestByType = new Dictionary<equipmentSO.EquipmentSpecialEffectType, GeneratedEffectValue>();
for (int i = 0; i < effects.Count; i++)
{
GeneratedEffectValue candidate = effects[i];
if (!bestByType.TryGetValue(candidate.effectType, out GeneratedEffectValue existing))
{
bestByType[candidate.effectType] = candidate;
continue;
}
bestByType[candidate.effectType] = ChoosePreferred(existing, candidate);
}
effects.Clear();
foreach (GeneratedEffectValue value in bestByType.Values)
{
effects.Add(value);
}
}
private static GeneratedEffectValue ChoosePreferred(GeneratedEffectValue left, GeneratedEffectValue right)
{
bool leftNegative = left.value < 0f;
bool rightNegative = right.value < 0f;
if (leftNegative && rightNegative)
{
return left.value <= right.value ? left : right;
}
if (!leftNegative && !rightNegative)
{
return left.value >= right.value ? left : right;
}
return Mathf.Abs(left.value) >= Mathf.Abs(right.value) ? left : right;
}
private static float AvoidZero(float minValue, float maxValue, float value)
{
if (!Mathf.Approximately(value, 0f))
{
return value;
}
if (minValue > 0f || maxValue < 0f)
{
return value;
}
float epsilon = Mathf.Min(0.0001f, Mathf.Max(Mathf.Abs(minValue), Mathf.Abs(maxValue), 0.0001f));
return UnityEngine.Random.value < 0.5f ? -epsilon : epsilon;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4699aa930794f4f4badbd9f635b82a98
+95 -29
View File
@@ -1,9 +1,21 @@
using System;
using System;
using UnityEngine;
[CreateAssetMenu(fileName = "NewEquipment", menuName = "Equipment/Equipment SO")]
public class equipmentSO : ScriptableObject
{
public enum EquipmentSkillType
{
,
,
,
,
,
,
,
}
public enum EquipmentSpecialEffectType
{
MaxHp,
@@ -23,9 +35,6 @@ public class equipmentSO : ScriptableObject
[Range(-0.1f, 0.1f)]
public float basicGain = 0f;
public float randomRangeStart = 0f;
public float randomRangeEnd = 0f;
[Min(0f)]
public float cultivationInterval = 0f;
@@ -33,13 +42,6 @@ public class equipmentSO : ScriptableObject
{
basicGain = Mathf.Clamp(basicGain, -0.1f, 0.1f);
cultivationInterval = Mathf.Max(0f, cultivationInterval);
if (randomRangeEnd < randomRangeStart)
{
float cached = randomRangeStart;
randomRangeStart = randomRangeEnd;
randomRangeEnd = cached;
}
}
}
@@ -47,7 +49,7 @@ public class equipmentSO : ScriptableObject
public class EquipmentTierPresentation
{
public string tierName;
public Sprite tierIcon;
public Sprite equipmentSprite;
[TextArea(2, 6)] public string tierDescription;
}
@@ -56,13 +58,14 @@ public class equipmentSO : ScriptableObject
{
public EquipmentSpecialEffectType effectType;
public float value;
public string displayName;
public Sprite displayIcon;
}
[Header("技能类型")]
public EquipmentSkillType skillType;
[Header("Basic Attributes")]
[Min(1)] public int level = 1;
public EquipmentTierPresentation[] tierPresentations = new EquipmentTierPresentation[5];
[Min(0)] public int level = 0;
public equipmentTierNameConfigSO tierNameConfig;
[Header("Max HP")]
public EquipmentStatTuning maxHp = new EquipmentStatTuning();
@@ -79,31 +82,94 @@ public class equipmentSO : ScriptableObject
[Header("Score Efficiency")]
public EquipmentStatTuning scoreEfficiency = new EquipmentStatTuning();
[Header("Effect Rules")]
public bool onlyProduceSameTypeAttributes = false;
[Header("Special Effects")]
public EquipmentSpecialEffect[] specialEffects = Array.Empty<EquipmentSpecialEffect>();
[Header("是否共鸣")]
public bool enableTypeSameEffects = false;
[Header("共鸣特效")]
public EquipmentSpecialEffect[] typeSameEffects = Array.Empty<EquipmentSpecialEffect>();
[Header("幻化效果")]
public EquipmentSpecialEffect[] illusionEffects = Array.Empty<EquipmentSpecialEffect>();
[Header("满级效果")]
public EquipmentSpecialEffect[] maxLevelEffects = Array.Empty<EquipmentSpecialEffect>();
[Header("携带技能id")]
public int sa_skillID;
public int ia_skillID;
public int GetTierStageIndex()
{
if (level >= 20)
{
return 4;
}
if (level >= 15)
{
return 3;
}
if (level >= 10)
{
return 2;
}
if (level >= 5)
{
return 1;
}
return 0;
}
public EquipmentTierPresentation GetCurrentTierPresentation()
{
return GetTierPresentationByStageIndex(GetTierStageIndex());
}
public EquipmentTierPresentation GetTierPresentationByStageIndex(int stageIndex)
{
if (tierNameConfig == null)
{
return null;
}
if (tierNameConfig.TryGetStagePresentation(skillType, stageIndex, out equipmentTierNameConfigSO.StagePresentation configured))
{
return new EquipmentTierPresentation
{
tierName = configured.tierName,
equipmentSprite = configured.equipmentSprite,
tierDescription = configured.tierDescription
};
}
return null;
}
public string GetCurrentTierDisplayName()
{
EquipmentTierPresentation current = GetCurrentTierPresentation();
return current != null ? current.tierName : string.Empty;
}
public Sprite GetCurrentEquipmentSprite()
{
EquipmentTierPresentation current = GetCurrentTierPresentation();
return current != null ? current.equipmentSprite : null;
}
private void OnValidate()
{
level = Mathf.Max(1, level);
level = Mathf.Max(0, level);
maxHp?.Normalize();
attack?.Normalize();
maxMana?.Normalize();
damageResistance?.Normalize();
scoreEfficiency?.Normalize();
if (tierPresentations == null)
{
tierPresentations = new EquipmentTierPresentation[5];
}
else if (tierPresentations.Length != 5)
{
Array.Resize(ref tierPresentations, 5);
}
}
}
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "NewEquipmentTierNameConfig", menuName = "Equipment/Equipment Tier Name Config")]
public class equipmentTierNameConfigSO : ScriptableObject
{
[Serializable]
public class StagePresentation
{
public string tierName;
public Sprite equipmentSprite;
[TextArea(2, 6)] public string tierDescription;
}
[Serializable]
public class SkillTypePresentationSet
{
public equipmentSO.EquipmentSkillType skillType;
public StagePresentation[] stagePresentations = new StagePresentation[5];
public void EnsureFiveStages()
{
if (stagePresentations == null)
{
stagePresentations = new StagePresentation[5];
}
else if (stagePresentations.Length != 5)
{
Array.Resize(ref stagePresentations, 5);
}
for (int i = 0; i < stagePresentations.Length; i++)
{
if (stagePresentations[i] == null)
{
stagePresentations[i] = new StagePresentation();
}
}
}
}
[Header("按技能类型配置五阶段展示")]
public List<SkillTypePresentationSet> namingSets = new List<SkillTypePresentationSet>();
private void OnValidate()
{
EnsureAllSkillTypes();
}
public bool TryGetStagePresentation(equipmentSO.EquipmentSkillType skillType, int stageIndex, out StagePresentation presentation)
{
EnsureAllSkillTypes();
SkillTypePresentationSet set = FindSet(skillType);
if (set != null)
{
int clampedIndex = Mathf.Clamp(stageIndex, 0, 4);
presentation = set.stagePresentations[clampedIndex];
return presentation != null;
}
presentation = null;
return false;
}
public bool TryGetAllStagePresentations(equipmentSO.EquipmentSkillType skillType, out StagePresentation[] presentations)
{
EnsureAllSkillTypes();
SkillTypePresentationSet set = FindSet(skillType);
if (set != null)
{
presentations = set.stagePresentations;
return true;
}
presentations = null;
return false;
}
private void EnsureAllSkillTypes()
{
if (namingSets == null)
{
namingSets = new List<SkillTypePresentationSet>();
}
var normalized = new List<SkillTypePresentationSet>();
Array skillTypes = Enum.GetValues(typeof(equipmentSO.EquipmentSkillType));
for (int i = 0; i < skillTypes.Length; i++)
{
equipmentSO.EquipmentSkillType skillType = (equipmentSO.EquipmentSkillType)skillTypes.GetValue(i);
SkillTypePresentationSet set = FindSet(skillType);
if (set == null)
{
set = new SkillTypePresentationSet
{
skillType = skillType
};
}
set.skillType = skillType;
set.EnsureFiveStages();
normalized.Add(set);
}
namingSets = normalized;
}
private SkillTypePresentationSet FindSet(equipmentSO.EquipmentSkillType skillType)
{
for (int i = 0; i < namingSets.Count; i++)
{
SkillTypePresentationSet set = namingSets[i];
if (set != null && set.skillType == skillType)
{
return set;
}
}
return null;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8dc6271282c80ec4387e3734f1157285
+8
View File
@@ -0,0 +1,8 @@
using UnityEngine;
using UnityEngine.UI;
public class esPrefab : MonoBehaviour
{
public Image esIcon;
public Text esName;
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 099deb535165a1d4bad59c389ff3e3dd