using Northbound.Data; using System.Collections.Generic; using Unity.Netcode; using UnityEngine; namespace Northbound { public class CreepCamp : NetworkBehaviour { [Header("Camp Settings")] [Tooltip("Creep prefabs available to spawn")] [SerializeField] private List creepPrefabs = new List(); private float _zPosition; private float _campStrength; private float _campCostBudget; private float _spawnRadius; private int _maxSpawnAttempts; public override void OnNetworkSpawn() { if (IsServer) { SpawnCreeps(); } } public void InitializeCamp(float zPosition, float strengthMultiplier, float costBudget, float radius, int maxAttempts) { _zPosition = zPosition; _campStrength = strengthMultiplier; _campCostBudget = costBudget; _spawnRadius = radius; _maxSpawnAttempts = maxAttempts; } public void SetCreepPrefabs(List prefabs) { creepPrefabs.Clear(); creepPrefabs.AddRange(prefabs); } private void SpawnCreeps() { if (creepPrefabs.Count == 0) { Debug.LogWarning($"[CreepCamp] No creep prefabs assigned!"); return; } float remainingCost = _campCostBudget * _campStrength; int spawnedCount = 0; for (int attempt = 0; attempt < _maxSpawnAttempts && remainingCost > 0; attempt++) { GameObject selectedCreep = SelectCreepByCost(remainingCost); if (selectedCreep == null) { Debug.LogWarning($"[CreepCamp] No affordable creeps. Remaining cost: {remainingCost:F2}"); break; } CreepData creepData = GetCreepDataFromPrefab(selectedCreep); if (creepData == null) { Debug.LogWarning($"[CreepCamp] Could not get creep data from {selectedCreep.name}"); continue; } SpawnCreep(selectedCreep); remainingCost -= creepData.cost; spawnedCount++; } Debug.Log($"[CreepCamp] Spawned {spawnedCount} creeps (Cost budget: {_campCostBudget * _campStrength:F2}, Used: {(_campCostBudget * _campStrength) - remainingCost:F2})"); } private GameObject SelectCreepByCost(float remainingCost) { List affordableCreeps = new List(); foreach (var prefab in creepPrefabs) { CreepData creepData = GetCreepDataFromPrefab(prefab); if (creepData != null && creepData.cost <= remainingCost) { affordableCreeps.Add(prefab); } } if (affordableCreeps.Count == 0) { return null; } float totalWeight = 0f; foreach (var prefab in affordableCreeps) { CreepData creepData = GetCreepDataFromPrefab(prefab); if (creepData != null) { totalWeight += creepData.weight; } } if (totalWeight == 0f) { return affordableCreeps[Random.Range(0, affordableCreeps.Count)]; } float randomValue = Random.Range(0f, totalWeight); float cumulativeWeight = 0f; foreach (var prefab in affordableCreeps) { CreepData creepData = GetCreepDataFromPrefab(prefab); if (creepData != null) { cumulativeWeight += creepData.weight; if (randomValue <= cumulativeWeight) { return prefab; } } } return affordableCreeps[Random.Range(0, affordableCreeps.Count)]; } private bool CanSpawnAnyCreep(float remainingCost) { foreach (var prefab in creepPrefabs) { CreepData creepData = GetCreepDataFromPrefab(prefab); if (creepData != null && creepData.cost <= remainingCost) { return true; } } return false; } private CreepData GetCreepDataFromPrefab(GameObject prefab) { if (prefab == null) return null; CreepDataComponent component = prefab.GetComponent(); if (component != null) { return component.creepData; } return null; } private void SpawnCreep(GameObject prefab) { Vector3 spawnOffset = Random.insideUnitSphere * _spawnRadius; spawnOffset.y = 0; GameObject creep = Instantiate(prefab, transform.position + spawnOffset, Quaternion.identity); if (creep.GetComponent() == null) { var visibility = creep.AddComponent(); visibility.showInExploredAreas = false; visibility.updateInterval = 0.2f; } NetworkObject networkObj = creep.GetComponent(); if (networkObj == null) { networkObj = creep.AddComponent(); } networkObj.SpawnWithOwnership(NetworkManager.Singleton.LocalClientId); } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, _spawnRadius); } private void OnDrawGizmosSelected() { Gizmos.color = new Color(1f, 0f, 0f, 0.3f); Gizmos.DrawSphere(transform.position, _spawnRadius); } } }