885 lines
31 KiB
C#
885 lines
31 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using Bansonic;
|
|
#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();
|
|
}
|
|
|
|
equipBag[] bags = UnityEngine.Object.FindObjectsByType<equipBag>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
if (bags == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < bags.Length; i++)
|
|
{
|
|
if (bags[i] != null && bags[i] != targetEquipBag)
|
|
{
|
|
bags[i].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 = equipmentGenerator.GenerateUniqueEquipmentName(sourceEquipment != null ? sourceEquipment.skillType : 0);
|
|
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);
|
|
if (lastGeneratedEquipment != null)
|
|
{
|
|
gItemGet.display(gItemGet.FromEquipment(lastGeneratedEquipment, 1));
|
|
}
|
|
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 (!Application.isPlaying && 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 equipmentGenerator.RegisterGeneratedEquipment(generated);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|