装备系统做了很多
This commit is contained in:
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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}
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad117e8f9c5167944bbae4e991210308
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db343678ddc5fd44e971ffbe67d0ba5e
|
||||
@@ -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:
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class esPrefab : MonoBehaviour
|
||||
{
|
||||
public Image esIcon;
|
||||
public Text esName;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 099deb535165a1d4bad59c389ff3e3dd
|
||||
Reference in New Issue
Block a user