511 lines
26 KiB
C#
511 lines
26 KiB
C#
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
|
|
}
|
|
}
|