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(); [Header("Spawning Settings")] [Tooltip("Camp strength multiplier (higher = stronger creeps)")] [SerializeField] private float campStrength = 1f; [Tooltip("Cost budget for spawning creeps")] [SerializeField] private float campCostBudget = 10f; [Tooltip("Spawn radius around camp")] [SerializeField] private float spawnRadius = 5f; [Tooltip("Max creep spawn attempts")] [SerializeField] private int maxSpawnAttempts = 50; private float _zPosition; public override void OnNetworkSpawn() { if (IsServer) { SpawnCreeps(); } } public void InitializeCamp(float zPosition, float strengthMultiplier) { _zPosition = zPosition; campStrength = strengthMultiplier; } public void SetCreepPrefabs(List prefabs) { creepPrefabs.Clear(); creepPrefabs.AddRange(prefabs); Debug.Log($"[CreepCamp] SetCreepPrefabs called with {prefabs.Count} prefabs. Current count: {creepPrefabs.Count}"); } private void SpawnCreeps() { Debug.Log($"[CreepCamp] Starting creep spawn at Z={_zPosition:F1}, strength={campStrength:F2}x, prefabs={creepPrefabs.Count}"); if (creepPrefabs.Count == 0) { Debug.LogWarning($"[CreepCamp] No creep prefabs assigned!"); return; } float remainingCost = campCostBudget * campStrength; Debug.Log($"[CreepCamp] Cost budget: {campCostBudget} x {campStrength:F2} = {remainingCost:F2}"); int spawnedCount = 0; for (int attempt = 0; attempt < maxSpawnAttempts && remainingCost > 0; attempt++) { GameObject selectedCreep = SelectCreepByCost(remainingCost); if (selectedCreep == null) { Debug.LogWarning($"[CreepCamp] Could not select creep (attempt {attempt + 1}/{maxSpawnAttempts}), remaining cost: {remainingCost:F2}"); break; } CreepData creepData = GetCreepDataFromPrefab(selectedCreep); if (creepData == null) { Debug.LogWarning($"[CreepCamp] Could not get creep data from {selectedCreep.name}"); continue; } if (creepData.cost > remainingCost) { if (!CanSpawnAnyCreep(remainingCost)) { Debug.LogWarning($"[CreepCamp] No affordable creeps found. Remaining cost: {remainingCost:F2}"); break; } continue; } Debug.Log($"[CreepCamp] Spawning {selectedCreep.name} (cost: {creepData.cost}, remaining: {remainingCost:F2})"); SpawnCreep(selectedCreep); remainingCost -= creepData.cost; spawnedCount++; } Debug.Log($"[CreepCamp] Spawned {spawnedCount} creeps at Z={_zPosition:F1} with strength {campStrength:F2}x"); } 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.Spawn(); creep.transform.SetParent(transform); } 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); } } }