using System.Collections.Generic; using System.Linq; using InfinityPBR.ModularCharacterHelper; using Sirenix.OdinInspector; using Sirenix.Utilities; using UnityEngine; using VOID.Generic.Dict; using VOID.Generic.Objects.Unit; using VOID.Generic.Util; using Random = UnityEngine.Random; namespace VOID.ScriptableObjects { [CreateAssetMenu(menuName = "GAME DATA/Generator/Generator Jednostki")] public class UnitGenerator : ScriptableObject { [Title("Unit References")] [SerializeField] private UnitObject[] _unitPrefabs; [SerializeField] private Material[] _skinMaterials; [SerializeField] private Material[] _hairMaterials; [Space(100)] [Title("Model")] [InfoBox("If prefab part can't be attached to unit prefab then it'll be skipped!")] [SerializeField] private bool _generateHair; [SerializeField, ShowIf(nameof(_generateHair)), Required] private ModularPart[] _hairPrefabs; [Title("Colors")] [InfoBox("If colors list is empty then randomize new one!")] [SerializeField] private bool _generateSkinColor; [SerializeField, ShowIf(nameof(_generateSkinColor))] private Color[] _skinColors; [SerializeField] private bool _generateHairColor; [SerializeField, ShowIf(nameof(_generateHairColor))] private Color[] _hairColors; [Title("Main Attributes")] [SerializeField] private bool _generateMainAttributes; [SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _strength = new(4, 7); [SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _dexterity = new(4, 7); [SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _intelligence = new(4, 7); [SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _constitution = new(4, 7); [SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _speed = new(4, 7); [SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _perception = new(4, 7); private void OnValidate() { if (!_generateHair) { _hairPrefabs = null; } if (!_generateSkinColor) { _skinColors = null; } if (!_generateHairColor) { _hairColors = null; } if (!_generateMainAttributes) { _strength = new Vector2Int(4, 7); _dexterity = new Vector2Int(4, 7); _intelligence = new Vector2Int(4, 7); _constitution = new Vector2Int(4, 7); _speed = new Vector2Int(4, 7); _perception = new Vector2Int(4, 7); } } /// /// Generate new :
/// 1. Selects random prefab
/// 2. Wait for full initialization of
/// 3. Updates with random things defined via inspector ///
/// Instantiated random public UnitObject Generate(int? seed = null) { if (seed.HasValue) RandomUtil.InitState(seed.Value); var unit = Instantiate(RandomUtil.RandomElement(_unitPrefabs)); Randomize(unit); return unit; } private void Randomize(UnitObject unit) { RandomizeHair(unit); RandomizeSkinColor(unit); RandomizeHairColor(unit); RandomizeMainAttributes(unit); } private void RandomizeHair(UnitObject unit) { if (!_generateHair) return; var modularCharacter = unit.unitState.modularCharacter; var validHairPrefabs = _hairPrefabs.Where(hair => hair.avatar == modularCharacter.avatar).ToList(); if (validHairPrefabs.IsNullOrEmpty()) return; modularCharacter.AttachPart(Instantiate(RandomUtil.RandomElement(validHairPrefabs), unit.transform)); } private void RandomizeSkinColor(UnitObject unit) { if (!_generateSkinColor) return; if (_skinMaterials.IsNullOrEmpty()) return; ApplyTintToMaterials(unit, _skinColors, _skinMaterials); } private void RandomizeHairColor(UnitObject unit) { if (!_generateHairColor) return; if (_hairMaterials.IsNullOrEmpty()) return; ApplyTintToMaterials(unit, _hairColors, _hairMaterials); } private void ApplyTintToMaterials(UnitObject unit, Color[] colors, Material[] forMaterials) { // Find renderers with this material to add tint color var foundRenderers = unit.GetComponentsInChildren() .Where(renderer => forMaterials.Any(material => renderer.sharedMaterials.Contains(material))) .ToList(); if (foundRenderers.IsNullOrEmpty()) return; // Get random defined color if present OR randomize new one var color = colors.IsNullOrEmpty() ? Random.ColorHSV(0, 1, 0, 1, 0, 1, 0, 1) : RandomUtil.RandomElement(colors); // Normally renderers here will use shared materials, but we want to create colored "variants" thats why // we need to instantiate material and add tint color if this is matching material. Other materials will // instantiate too anyway even without our help so lets do all of them by ourselfs! foreach (var foundRenderer in foundRenderers) { var materials = new List(); foreach (var sharedMaterial in foundRenderer.sharedMaterials) { if (forMaterials.Contains(sharedMaterial)) { var material = Instantiate(sharedMaterial); material.color = color; materials.Add(material); } else { materials.Add(sharedMaterial); } } foundRenderer.sharedMaterials = materials.ToArray(); } } private void RandomizeMainAttributes(UnitObject unit) { if (!_generateMainAttributes) return; unit.unitData.baseMainAttributes.Set(MainAttributeType.Strength, RandomUtil.RandomInteger(_strength.x, _strength.y)); unit.unitData.baseMainAttributes.Set(MainAttributeType.Dexterity, RandomUtil.RandomInteger(_dexterity.x, _dexterity.y)); unit.unitData.baseMainAttributes.Set(MainAttributeType.Intelligence, RandomUtil.RandomInteger(_intelligence.x, _intelligence.y)); unit.unitData.baseMainAttributes.Set(MainAttributeType.Constitution, RandomUtil.RandomInteger(_constitution.x, _constitution.y)); unit.unitData.baseMainAttributes.Set(MainAttributeType.Speed, RandomUtil.RandomInteger(_speed.x, _speed.y)); unit.unitData.baseMainAttributes.Set(MainAttributeType.Perception, RandomUtil.RandomInteger(_perception.x, _perception.y)); } } }