RiftMayhem/Assets/Scripts/Items/Generator/EquippableItemGenerator.cs

655 lines
23 KiB
C#

using Kryz.CharacterStats.Examples;
using System.Collections.Generic;
using UnityEngine;
public class EquippableItemGenerator : MonoBehaviour
{
[Header("Generation Settings")]
public int minStatRolls = 2;
public int maxStatRolls = 6;
public float baseStatValue = 10f;
public float statVariance = 0.3f; // 30% variance
public float percentStatBaseValue = 0.05f; // 5% base for percent stats
[Header("Stat Roll Weights by Equipment Type")]
[SerializeField] private StatWeights armorWeights = new StatWeights();
[SerializeField] private StatWeights weaponWeights = new StatWeights();
public List<Sprite> HelmetIcons = new List<Sprite>();
public List<Sprite> ShoulderIcons = new List<Sprite>();
public List<Sprite> ChestIcons = new List<Sprite>();
public List<Sprite> BeltIcons = new List<Sprite>();
public List<Sprite> LegsIcons = new List<Sprite>();
public List<Sprite> BracersIcons = new List<Sprite>();
public List<Sprite> GlovesIcons = new List<Sprite>();
public List<Sprite> BootsIcons = new List<Sprite>();
public List<Sprite> StaffIcons = new List<Sprite>();
public List<Sprite> SpearIcons = new List<Sprite>();
public List<Sprite> ScytheIcons = new List<Sprite>();
public List<Sprite> HammerIcons = new List<Sprite>();
public List<Sprite> BowIcons = new List<Sprite>();
public List<Sprite> CrossbowIcons = new List<Sprite>();
public List<Sprite> AxeIcons = new List<Sprite>();
public List<Sprite> SwordIcons = new List<Sprite>();
public List<Sprite> ShieldIcons = new List<Sprite>();
public List<Sprite> DaggerIcons = new List<Sprite>();
public List<Sprite> BookIcons = new List<Sprite>();
[System.Serializable]
public class StatWeights
{
[Header("Damage Stats")]
public float attackDamage = 1f;
public float spellDamage = 1f;
public float critChance = 0.8f;
public float critDamage = 0.8f;
[Header("Defensive Stats")]
public float maxHealth = 1f;
public float armor = 1f;
public float magicResistance = 1f;
public float dodgeChance = 0.6f;
public float blockChance = 0.4f;
public float blockEffectiveness = 0.4f;
[Header("Resource Stats")]
public float healthRegen = 0.7f;
public float maxMana = 0.8f;
public float manaRegen = 0.7f;
[Header("Utility Stats")]
public float attackSpeed = 0.8f;
public float areaEffectiveness = 0.5f;
public float cooldownReduction = 0.6f;
public float movementSpeed = 0.4f;
public float reputationGain = 0.3f;
public float goldCostReduction = 0.3f;
}
public enum ItemTier
{
Common,
Uncommon,
Rare,
Epic,
Legendary
}
[ContextMenu("Update Lists From Resources")]
private void UpdateListsFromResources()
{
// Armor pieces
HelmetIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Helmets"))
{
HelmetIcons.Add(sprite);
}
ShoulderIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Shoulders"))
{
ShoulderIcons.Add(sprite);
}
ChestIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Chests"))
{
ChestIcons.Add(sprite);
}
BeltIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Belts"))
{
BeltIcons.Add(sprite);
}
LegsIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Legs"))
{
LegsIcons.Add(sprite);
}
BracersIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Bracers"))
{
BracersIcons.Add(sprite);
}
GlovesIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Gloves"))
{
GlovesIcons.Add(sprite);
}
BootsIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Armor/Boots"))
{
BootsIcons.Add(sprite);
}
// Two-handed weapons
StaffIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Staffs"))
{
StaffIcons.Add(sprite);
}
SpearIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Spears"))
{
SpearIcons.Add(sprite);
}
ScytheIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Scythes"))
{
ScytheIcons.Add(sprite);
}
HammerIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Hammers"))
{
HammerIcons.Add(sprite);
}
BowIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Bows"))
{
BowIcons.Add(sprite);
}
CrossbowIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Crossbows"))
{
CrossbowIcons.Add(sprite);
}
AxeIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Axes"))
{
AxeIcons.Add(sprite);
}
// One-handed weapons
SwordIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Swords"))
{
SwordIcons.Add(sprite);
}
ShieldIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Shields"))
{
ShieldIcons.Add(sprite);
}
DaggerIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Daggers"))
{
DaggerIcons.Add(sprite);
}
BookIcons.Clear();
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Weapons/Books"))
{
BookIcons.Add(sprite);
}
Debug.Log("Updated all icon lists from Resources folders");
}
public EquippableItemInstance GenerateEquippableItemInstance()
{
EquippableItemInstance generatedItem = new EquippableItemInstance();
//Do stuff
return generatedItem;
}
[ContextMenu("Generate Random Item To Inventory")]
private void TestGenerateItemToInventory()
{
EquipmentType typeToGenerate = (EquipmentType)Random.Range(0, 10);
if (typeToGenerate == EquipmentType.Weapon1 || typeToGenerate == EquipmentType.Weapon2)
{
WeaponType weaponType = (WeaponType)Random.Range(0, 11);
Inventory.Instance.AddItem(GenerateWeapon(weaponType, (ItemTier)Random.Range(0, 5), 1));
}
else
{
Inventory.Instance.AddItem(GenerateEquippableItemInstance(typeToGenerate, (ItemTier)Random.Range(0, 5), 1));
}
}
public EquippableItemInstance GenerateEquippableItemInstance(EquipmentType equipmentType, ItemTier tier = ItemTier.Common, int playerLevel = 1)
{
EquippableItemInstance item = new EquippableItemInstance();
// Set basic properties
item.EquipmentType = equipmentType;
item.ItemName = GenerateItemName(equipmentType, tier);
item.Icon = GetRandomIcon(equipmentType);
Debug.Log("Generated: " + item.ItemName + " icon " + item.Icon.name);
// Set weapon type if it's a weapon
if (equipmentType == EquipmentType.Weapon1 || equipmentType == EquipmentType.Weapon2)
{
item.WeaponType = GetRandomWeaponType();
}
// Generate stats based on tier and level
GenerateStatsForItem(item, tier, playerLevel);
Debug.Log("Generated: " + item.ItemName + " icon " + item.Icon.name);
return item;
}
// Generate weapon by weapon type (recommended approach)
public EquippableItemInstance GenerateWeapon(WeaponType weaponType, ItemTier tier = ItemTier.Common, int playerLevel = 1)
{
EquippableItemInstance item = new EquippableItemInstance();
// All weapons use Weapon1 as default - the equipment system handles slot assignment
item.EquipmentType = EquipmentType.Weapon1;
item.WeaponType = weaponType;
item.ItemName = GenerateWeaponName(weaponType, tier);
item.Icon = GetWeaponIcon(weaponType);
Debug.Log("Generated: " + item.ItemName + " icon " + item.Icon.name);
GenerateStatsForItem(item, tier, playerLevel);
Debug.Log("Generated: " + item.ItemName + " icon " + item.Icon.name);
return item;
}
// Alternative: Let caller specify which slot they want
public EquippableItemInstance GenerateWeapon(WeaponType weaponType, EquipmentType weaponSlot, ItemTier tier = ItemTier.Common, int playerLevel = 1)
{
if (weaponSlot != EquipmentType.Weapon1 && weaponSlot != EquipmentType.Weapon2)
weaponSlot = EquipmentType.Weapon1; // Default fallback
EquippableItemInstance item = new EquippableItemInstance();
item.EquipmentType = weaponSlot;
item.WeaponType = weaponType;
item.ItemName = GenerateWeaponName(weaponType, tier);
item.Icon = GetWeaponIcon(weaponType);
GenerateStatsForItem(item, tier, playerLevel);
return item;
}
private void GenerateStatsForItem(EquippableItemInstance item, ItemTier tier, int playerLevel)
{
// Determine number of stats based on tier
int statCount = GetStatCountForTier(tier);
float levelMultiplier = 1f + (playerLevel - 1) * 0.1f; // 10% increase per level
float tierMultiplier = GetTierMultiplier(tier);
// Get appropriate stat weights
StatWeights weights = item.IsWeapon ? weaponWeights : armorWeights;
// Roll stats
HashSet<string> rolledStats = new HashSet<string>();
for (int i = 0; i < statCount; i++)
{
RollRandomStat(item, weights, rolledStats, levelMultiplier * tierMultiplier);
}
}
private int GetStatCountForTier(ItemTier tier)
{
return tier switch
{
ItemTier.Common => Random.Range(1, 3),
ItemTier.Uncommon => Random.Range(2, 4),
ItemTier.Rare => Random.Range(3, 5),
ItemTier.Epic => Random.Range(4, 6),
ItemTier.Legendary => Random.Range(5, 7),
_ => 2
};
}
private float GetTierMultiplier(ItemTier tier)
{
return tier switch
{
ItemTier.Common => 1f,
ItemTier.Uncommon => 1.3f,
ItemTier.Rare => 1.7f,
ItemTier.Epic => 2.2f,
ItemTier.Legendary => 3f,
_ => 1f
};
}
private void RollRandomStat(EquippableItemInstance item, StatWeights weights, HashSet<string> rolledStats, float multiplier)
{
// Create weighted list of available stats
List<(string stat, float weight)> availableStats = new List<(string, float)>();
// Add damage stats if not already rolled
if (!rolledStats.Contains("AttackDamage"))
availableStats.Add(("AttackDamage", weights.attackDamage));
if (!rolledStats.Contains("SpellDamage"))
availableStats.Add(("SpellDamage", weights.spellDamage));
if (!rolledStats.Contains("CritChance"))
availableStats.Add(("CritChance", weights.critChance));
if (!rolledStats.Contains("CritDamage"))
availableStats.Add(("CritDamage", weights.critDamage));
// Add defensive stats
if (!rolledStats.Contains("MaxHealth"))
availableStats.Add(("MaxHealth", weights.maxHealth));
if (!rolledStats.Contains("Armor"))
availableStats.Add(("Armor", weights.armor));
if (!rolledStats.Contains("MagicResistance"))
availableStats.Add(("MagicResistance", weights.magicResistance));
if (!rolledStats.Contains("DodgeChance"))
availableStats.Add(("DodgeChance", weights.dodgeChance));
if (!rolledStats.Contains("BlockChance"))
availableStats.Add(("BlockChance", weights.blockChance));
if (!rolledStats.Contains("BlockEffectiveness"))
availableStats.Add(("BlockEffectiveness", weights.blockEffectiveness));
// Add resource stats
if (!rolledStats.Contains("HealthRegen"))
availableStats.Add(("HealthRegen", weights.healthRegen));
if (!rolledStats.Contains("MaxMana"))
availableStats.Add(("MaxMana", weights.maxMana));
if (!rolledStats.Contains("ManaRegen"))
availableStats.Add(("ManaRegen", weights.manaRegen));
// Add utility stats
if (!rolledStats.Contains("AttackSpeed"))
availableStats.Add(("AttackSpeed", weights.attackSpeed));
if (!rolledStats.Contains("AreaEffectiveness"))
availableStats.Add(("AreaEffectiveness", weights.areaEffectiveness));
if (!rolledStats.Contains("CooldownReduction"))
availableStats.Add(("CooldownReduction", weights.cooldownReduction));
if (!rolledStats.Contains("MovementSpeed"))
availableStats.Add(("MovementSpeed", weights.movementSpeed));
if (!rolledStats.Contains("ReputationGain"))
availableStats.Add(("ReputationGain", weights.reputationGain));
if (!rolledStats.Contains("GoldCostReduction"))
availableStats.Add(("GoldCostReduction", weights.goldCostReduction));
if (availableStats.Count == 0) return;
// Weighted random selection
string selectedStat = SelectWeightedRandom(availableStats);
rolledStats.Add(selectedStat);
// Apply the stat
ApplyStatToItem(item, selectedStat, multiplier);
}
private string SelectWeightedRandom(List<(string stat, float weight)> weightedStats)
{
float totalWeight = 0f;
foreach (var stat in weightedStats)
totalWeight += stat.weight;
float randomValue = Random.Range(0f, totalWeight);
float currentWeight = 0f;
foreach (var stat in weightedStats)
{
currentWeight += stat.weight;
if (randomValue <= currentWeight)
return stat.stat;
}
return weightedStats[0].stat; // Fallback
}
private void ApplyStatToItem(EquippableItemInstance item, string statName, float multiplier)
{
// Decide between flat or percent bonus (roughly 60% flat, 40% percent)
bool usePercent = Random.value < 0.4f;
switch (statName)
{
case "AttackDamage":
if (usePercent)
item.AttackDamagePercentBonus = GeneratePercentStat(multiplier);
else
item.AttackDamageBonus = GenerateFlatStat(multiplier);
break;
case "SpellDamage":
if (usePercent)
item.SpellDamagePercentBonus = GeneratePercentStat(multiplier);
else
item.SpellDamageBonus = GenerateFlatStat(multiplier);
break;
case "CritChance":
if (usePercent)
item.CritChancePercentBonus = GeneratePercentStat(multiplier * 0.3f); // Lower values for crit
else
item.CritChanceBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier * 0.5f));
break;
case "CritDamage":
if (usePercent)
item.CritDamagePercentBonus = GeneratePercentStat(multiplier * 0.5f);
else
item.CritDamageBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier * 0.8f));
break;
case "MaxHealth":
if (usePercent)
item.MaxHealthPercentBonus = GeneratePercentStat(multiplier);
else
item.MaxHealthBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier * 5f)); // Health gets higher flat values
break;
case "Armor":
if (usePercent)
item.ArmorPercentBonus = GeneratePercentStat(multiplier);
else
item.ArmorBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier));
break;
case "MagicResistance":
if (usePercent)
item.MagicResistancePercentBonus = GeneratePercentStat(multiplier);
else
item.MagicResistanceBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier));
break;
case "DodgeChance":
item.DodgeChancePercentBonus = GeneratePercentStat(multiplier * 0.4f); // Always percent
break;
case "BlockChance":
item.BlockChancePercentBonus = GeneratePercentStat(multiplier * 0.4f); // Always percent
break;
case "BlockEffectiveness":
item.BlockEffectivenessPercentBonus = GeneratePercentStat(multiplier * 0.6f); // Always percent
break;
case "AttackSpeed":
item.AttackSpeedPercentBonus = GeneratePercentStat(multiplier * 0.6f); // Always percent
break;
case "HealthRegen":
if (usePercent)
item.HealthRegenPercentBonus = GeneratePercentStat(multiplier);
else
item.HealthRegenBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier * 2f));
break;
case "MaxMana":
if (usePercent)
item.MaxManaPercentBonus = GeneratePercentStat(multiplier);
else
item.MaxManaBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier * 3f));
break;
case "ManaRegen":
if (usePercent)
item.ManaRegenPercentBonus = GeneratePercentStat(multiplier);
else
item.ManaRegenBonus = Mathf.RoundToInt(GenerateFlatStat(multiplier * 2f));
break;
case "AreaEffectiveness":
item.AreaEffectivenessPercentBonus = GeneratePercentStat(multiplier * 0.5f); // Always percent
break;
case "CooldownReduction":
item.CooldownReductionPercentBonus = GeneratePercentStat(multiplier * 0.4f); // Always percent
break;
case "MovementSpeed":
item.MovementSpeedPercentBonus = GeneratePercentStat(multiplier * 0.3f); // Always percent
break;
case "ReputationGain":
item.ReputationGainIncreasePercentBonus = GeneratePercentStat(multiplier * 0.6f); // Always percent
break;
case "GoldCostReduction":
item.GoldCostReductionPercentBonus = GeneratePercentStat(multiplier * 0.5f); // Always percent
break;
}
}
private int GenerateFlatStat(float multiplier)
{
float baseValue = baseStatValue * multiplier;
float variance = baseValue * statVariance;
float finalValue = Random.Range(baseValue - variance, baseValue + variance);
return Mathf.Max(1, Mathf.RoundToInt(finalValue));
}
private float GeneratePercentStat(float multiplier)
{
float baseValue = percentStatBaseValue * multiplier;
float variance = baseValue * statVariance;
float finalValue = Random.Range(baseValue - variance, baseValue + variance);
return Mathf.Max(0.01f, Mathf.Round(finalValue * 1000f) / 1000f); // Round to 3 decimal places
}
private string GenerateItemName(EquipmentType equipmentType, ItemTier tier)
{
string[] tierPrefixes = tier switch
{
ItemTier.Common => new[] { "", "Simple", "Basic" },
ItemTier.Uncommon => new[] { "Fine", "Quality", "Enhanced" },
ItemTier.Rare => new[] { "Superior", "Masterwork", "Refined" },
ItemTier.Epic => new[] { "Exceptional", "Legendary", "Mythic" },
ItemTier.Legendary => new[] { "Divine", "Ancient", "Celestial" },
_ => new[] { "" }
};
string prefix = tierPrefixes[Random.Range(0, tierPrefixes.Length)];
string baseName = equipmentType.ToString();
return string.IsNullOrEmpty(prefix) ? baseName : $"{prefix} {baseName}";
}
private string GenerateWeaponName(WeaponType weaponType, ItemTier tier)
{
string[] tierPrefixes = tier switch
{
ItemTier.Common => new[] { "", "Simple", "Basic" },
ItemTier.Uncommon => new[] { "Fine", "Quality", "Enhanced" },
ItemTier.Rare => new[] { "Superior", "Masterwork", "Refined" },
ItemTier.Epic => new[] { "Exceptional", "Legendary", "Mythic" },
ItemTier.Legendary => new[] { "Divine", "Ancient", "Celestial" },
_ => new[] { "" }
};
string prefix = tierPrefixes[Random.Range(0, tierPrefixes.Length)];
string baseName = weaponType.ToString();
return string.IsNullOrEmpty(prefix) ? baseName : $"{prefix} {baseName}";
}
private Sprite GetRandomIcon(EquipmentType equipmentType)
{
List<Sprite> iconList = equipmentType switch
{
EquipmentType.Helmet => HelmetIcons,
EquipmentType.Shoulder => ShoulderIcons,
EquipmentType.Chest => ChestIcons,
EquipmentType.Belt => BeltIcons,
EquipmentType.Legs => LegsIcons,
EquipmentType.Bracers => BracersIcons,
EquipmentType.Gloves => GlovesIcons,
EquipmentType.Boots => BootsIcons,
EquipmentType.Weapon1 => null, // Will be handled by weapon type
EquipmentType.Weapon2 => null, // Will be handled by weapon type
_ => null
};
if (iconList != null && iconList.Count > 0)
return iconList[Random.Range(0, iconList.Count)];
return null;
}
private Sprite GetWeaponIcon(WeaponType weaponType)
{
List<Sprite> iconList = weaponType switch
{
WeaponType.Staff => StaffIcons,
WeaponType.Spear => SpearIcons,
WeaponType.Scythe => ScytheIcons,
WeaponType.Hammer => HammerIcons,
WeaponType.Bow => BowIcons,
WeaponType.Crossbow => CrossbowIcons,
WeaponType.Axe => AxeIcons,
WeaponType.Sword => SwordIcons,
WeaponType.Shield => ShieldIcons,
WeaponType.Dagger => DaggerIcons,
WeaponType.Book => BookIcons,
_ => SwordIcons
};
if (iconList != null && iconList.Count > 0)
return iconList[Random.Range(0, iconList.Count)];
return null;
}
private WeaponType GetRandomWeaponType()
{
// Return any weapon type
System.Array allTypes = System.Enum.GetValues(typeof(WeaponType));
return (WeaponType)allTypes.GetValue(Random.Range(0, allTypes.Length));
}
private void GenerateHelmet(EquippableItemInstance item)
{
}
private void RollDamageStats(EquippableItemInstance item)
{
int addedDamageStats = 0;
}
private void RollOffensiveStats(EquippableItemInstance item)
{
int addedOffensiveStats = 0;
}
private void RollDefensiveStats(EquippableItemInstance item)
{
int addedDefensiveStats = 0;
}
private void RollResourceStats(EquippableItemInstance item)
{
int addedResourceStats = 0;
}
private void RollControlStats(EquippableItemInstance item)
{
int addedControlStats = 0;
}
}