using System; using System.Collections.Generic; using UnityEngine; namespace Heroes.Battle { /// /// Container of all obstacles and per-terrain background sprites used by /// the generator and the view. Generator reads it as pure data; view uses /// it to resolve sprites during deployment. /// [CreateAssetMenu(menuName = "Heroes/Battle/Obstacle Database", fileName = "ObstacleDatabase")] public sealed class ObstacleDatabase : ScriptableObject { [Tooltip("All known obstacles. Filtered by allowed terrain at generation time.")] public List obstacles = new List(); [Tooltip("Background sprite variants for each terrain. Generator picks one at random.")] public List backgrounds = new List(); [Header("Generation")] [Tooltip("Inclusive minimum number of usual obstacles to attempt.")] [Min(0)] public int minObstacles = 5; [Tooltip("Inclusive maximum number of usual obstacles to attempt.")] [Min(0)] public int maxObstacles = 15; [Tooltip("Placement retry attempts per obstacle. H3 gives up after a handful of tries.")] [Min(1)] public int placementAttemptsPerObstacle = 20; [Tooltip("Probability (0..1) of placing an absolute obstacle when one is available for the terrain.")] [Range(0f, 1f)] public float absoluteObstacleChance = 0.5f; public IEnumerable GetObstaclesForTerrain(TerrainType terrain) { return GetObstaclesForTerrain(terrain, null); } public IEnumerable GetObstaclesForTerrain(TerrainType terrain, ObstacleType? typeFilter) { if (obstacles == null) yield break; foreach (var o in obstacles) { if (o == null) continue; if (typeFilter.HasValue && o.type != typeFilter.Value) continue; if (o.allowedTerrains == null || o.allowedTerrains.Count == 0) continue; if (o.allowedTerrains.Contains(terrain)) yield return o; } } public TerrainBackground FindBackgrounds(TerrainType terrain) { if (backgrounds == null) return null; foreach (var b in backgrounds) { if (b != null && b.terrain == terrain) return b; } return null; } public ObstacleDefinition FindById(string obstacleId) { if (obstacles == null || string.IsNullOrEmpty(obstacleId)) return null; foreach (var o in obstacles) { if (o != null && o.ResolveId() == obstacleId) return o; } return null; } } [Serializable] public sealed class TerrainBackground { public TerrainType terrain; [Tooltip("One or more sprite variants. Generator picks one at random.")] public List variants = new List(); public string ResolveVariantId(int index) { if (variants == null || variants.Count == 0) return terrain.ToString(); index = Mathf.Clamp(index, 0, variants.Count - 1); var s = variants[index]; return s != null ? s.name : $"{terrain}#{index}"; } public Sprite GetVariantById(string id) { if (variants == null) return null; foreach (var s in variants) { if (s != null && s.name == id) return s; } return variants.Count > 0 ? variants[0] : null; } } }