using UnityEngine; using System.Collections.Generic; using System.Linq; public class StaffManager : MonoBehaviour { public static StaffManager Instance { get; private set; } [Header("Staff Management")] [SerializeField] private List allStaff = new List(); [SerializeField] private int maxStaffCount = 50; [Header("Hiring Settings")] [SerializeField] private float baseHiringCost = 1000f; [SerializeField] private float dailyWageCost = 100f; [Header("Staff Prefabs")] [SerializeField] private GameObject receptionistPrefab; [SerializeField] private GameObject housekeeperPrefab; [SerializeField] private GameObject chefPrefab; [SerializeField] private GameObject janitorPrefab; [SerializeField] private GameObject bellhopPrefab; [SerializeField] private GameObject valetPrefab; [SerializeField] private GameObject defaultStaffPrefab; [Header("Spawn Points")] [SerializeField] private Transform staffSpawnPoint; private Queue pendingTasks = new Queue(); private Dictionary> staffByType = new Dictionary>(); // Events public System.Action OnStaffHired; public System.Action OnStaffFired; public System.Action OnTaskCreated; public System.Action OnTaskCompleted; private void Awake() { if (Instance != null && Instance != this) { Destroy(this.gameObject); return; } Instance = this; } private void Start() { InitializeStaffCategories(); SubscribeToEvents(); SetupSpawnPoint(); // Hire initial staff HireInitialStaff(); } private void OnDestroy() { UnsubscribeFromEvents(); } private void Update() { ProcessPendingTasks(); AutoAssignTasks(); } #region Initialization private void InitializeStaffCategories() { foreach (Staff.StaffType staffType in System.Enum.GetValues(typeof(Staff.StaffType))) { staffByType[staffType] = new List(); } } private void SubscribeToEvents() { Staff.OnStaffHired += OnStaffHiredHandler; Staff.OnStaffCompleteTask += OnStaffCompleteTaskHandler; Staff.OnTaskAssigned += OnTaskAssignedHandler; // Subscribe to guest events to create tasks if (HotelManager.Instance != null) { HotelManager.Instance.OnGuestArrived += OnGuestArrived; } } private void UnsubscribeFromEvents() { Staff.OnStaffHired -= OnStaffHiredHandler; Staff.OnStaffCompleteTask -= OnStaffCompleteTaskHandler; Staff.OnTaskAssigned -= OnTaskAssignedHandler; if (HotelManager.Instance != null) { HotelManager.Instance.OnGuestArrived -= OnGuestArrived; } } private void SetupSpawnPoint() { if (staffSpawnPoint == null) { GameObject spawn = new GameObject("Staff Spawn Point"); spawn.transform.position = new Vector3(-5f, 0f, -5f); staffSpawnPoint = spawn.transform; spawn.transform.SetParent(this.transform); } } private void HireInitialStaff() { // Hire minimum required staff HireStaff(Staff.StaffType.Receptionist); HireStaff(Staff.StaffType.Housekeeper); } #endregion #region Staff Hiring and Management public bool HireStaff(Staff.StaffType staffType) { if (allStaff.Count >= maxStaffCount) { Debug.LogWarning("Cannot hire more staff: Maximum capacity reached"); return false; } GameObject staffPrefab = GetStaffPrefab(staffType); if (staffPrefab == null) { Debug.LogWarning($"No prefab available for staff type: {staffType}"); return false; } // Spawn staff member Vector3 spawnPosition = staffSpawnPoint != null ? staffSpawnPoint.position : Vector3.zero; GameObject staffObj = Instantiate(staffPrefab, spawnPosition, Quaternion.identity); Staff staffComponent = staffObj.GetComponent(); if (staffComponent == null) { staffComponent = staffObj.AddComponent(); } // Set staff properties ConfigureNewStaff(staffComponent, staffType); Debug.Log($"Hired new {staffType}: {staffComponent.StaffName}"); return true; } private GameObject GetStaffPrefab(Staff.StaffType staffType) { switch (staffType) { case Staff.StaffType.Receptionist: return receptionistPrefab ?? CreateDefaultStaffPrefab("Receptionist", Color.blue); case Staff.StaffType.Housekeeper: return housekeeperPrefab ?? CreateDefaultStaffPrefab("Housekeeper", Color.green); case Staff.StaffType.Chef: return chefPrefab ?? CreateDefaultStaffPrefab("Chef", Color.red); case Staff.StaffType.Janitor: return janitorPrefab ?? CreateDefaultStaffPrefab("Janitor", Color.yellow); case Staff.StaffType.Bellhop: return bellhopPrefab ?? CreateDefaultStaffPrefab("Bellhop", Color.cyan); case Staff.StaffType.Valet: return valetPrefab ?? CreateDefaultStaffPrefab("Valet", Color.magenta); default: return defaultStaffPrefab ?? CreateDefaultStaffPrefab("Staff", Color.gray); } } private GameObject CreateDefaultStaffPrefab(string name, Color color) { GameObject staff = GameObject.CreatePrimitive(PrimitiveType.Capsule); staff.name = name; // Add NavMeshAgent with error handling try { var agent = staff.AddComponent(); agent.enabled = false; // Disable until NavMesh is available } catch (System.Exception e) { Debug.LogWarning($"Failed to add NavMeshAgent to {name}: {e.Message}. NavMesh needs to be baked first."); } // Set color staff.GetComponent().material.color = color; // Add Staff script will be added by the HireStaff method return staff; } private void ConfigureNewStaff(Staff staff, Staff.StaffType staffType) { // Set random efficiency float efficiency = UnityEngine.Random.Range(0.6f, 1f); // Configure based on type (using reflection or direct property access) staff.name = $"{staffType}_{allStaff.Count + 1}"; } public bool FireStaff(Staff staff) { if (staff == null || !allStaff.Contains(staff)) { return false; } // Clear all tasks staff.ClearAllTasks(); // Remove from lists allStaff.Remove(staff); foreach (var staffList in staffByType.Values) { staffList.Remove(staff); } OnStaffFired?.Invoke(staff); // Destroy the game object Destroy(staff.gameObject); Debug.Log($"Fired staff member: {staff.StaffName}"); return true; } public List GetStaffByType(Staff.StaffType staffType) { return staffByType.ContainsKey(staffType) ? new List(staffByType[staffType]) : new List(); } public List GetAvailableStaff(Staff.StaffType staffType) { return GetStaffByType(staffType).Where(s => s.IsAvailable).ToList(); } public List GetAllStaff() { return new List(allStaff); } public int GetStaffCount(Staff.StaffType staffType) { return GetStaffByType(staffType).Count; } #endregion #region Task Management public void CreateTask(TaskType taskType, Vector3 location, GameObject target = null, Room targetRoom = null, int priority = 1) { StaffTask task = new StaffTask { taskType = taskType, location = location, targetGuest = target, targetRoom = targetRoom, priority = priority, duration = GetTaskDuration(taskType), isUrgent = priority >= 8, description = GetTaskDescription(taskType) }; pendingTasks.Enqueue(task); OnTaskCreated?.Invoke(task); Debug.Log($"Created task: {taskType} at {location}"); } private void ProcessPendingTasks() { while (pendingTasks.Count > 0) { StaffTask task = pendingTasks.Dequeue(); if (AssignTaskToAvailableStaff(task)) { Debug.Log($"Task assigned: {task.taskType}"); } else { // Re-queue task if no available staff pendingTasks.Enqueue(task); break; // Avoid infinite loop } } } private bool AssignTaskToAvailableStaff(StaffTask task) { // Find staff members who can handle this task List capableStaff = allStaff.Where(s => s.CanHandleTask(task.taskType)).ToList(); if (capableStaff.Count == 0) { Debug.LogWarning($"No staff available to handle task: {task.taskType}"); return false; } // Find the best available staff member Staff bestStaff = capableStaff .Where(s => s.IsAvailable || s.TaskCount < 3) // Allow up to 3 queued tasks .OrderBy(s => s.TaskCount) .ThenByDescending(s => s.Efficiency) .FirstOrDefault(); if (bestStaff == null) { return false; // No available staff } bestStaff.AssignTask(task); return true; } private void AutoAssignTasks() { // Automatically create tasks based on hotel needs // Check if guests need check-in assistance if (HotelManager.Instance != null) { var waitingGuests = HotelManager.Instance.GetWaitingGuests(); foreach (var guest in waitingGuests) { if (guest.CurrentState == Guest.GuestState.LookingForReception) { CreateTask(TaskType.CheckInGuest, guest.transform.position, guest.gameObject, null, 7); } } } // Create random maintenance tasks if (UnityEngine.Random.value < 0.001f) // Very low chance per frame { CreateRandomMaintenanceTask(); } } private void CreateRandomMaintenanceTask() { TaskType[] maintenanceTasks = { TaskType.CleanArea, TaskType.Maintenance }; TaskType randomTask = maintenanceTasks[UnityEngine.Random.Range(0, maintenanceTasks.Length)]; Vector3 randomLocation = new Vector3( UnityEngine.Random.Range(-10f, 10f), 0f, UnityEngine.Random.Range(-10f, 10f) ); CreateTask(randomTask, randomLocation, null, null, 3); } private float GetTaskDuration(TaskType taskType) { switch (taskType) { case TaskType.CheckInGuest: return 15f; case TaskType.CleanRoom: return 30f; case TaskType.DeliverService: return 10f; case TaskType.PrepareFood: return 20f; case TaskType.AnswerPhone: return 5f; case TaskType.CarryLuggage: return 8f; case TaskType.ParkCar: return 12f; case TaskType.CleanArea: return 25f; case TaskType.Maintenance: return 45f; case TaskType.LaundryService: return 60f; default: return 15f; } } private string GetTaskDescription(TaskType taskType) { switch (taskType) { case TaskType.CheckInGuest: return "Check in arriving guest"; case TaskType.CleanRoom: return "Clean and prepare guest room"; case TaskType.DeliverService: return "Deliver room service"; case TaskType.PrepareFood: return "Prepare meal in kitchen"; case TaskType.AnswerPhone: return "Answer reception phone"; case TaskType.CarryLuggage: return "Assist guest with luggage"; case TaskType.ParkCar: return "Park guest's vehicle"; case TaskType.CleanArea: return "Clean common area"; case TaskType.Maintenance: return "Perform maintenance work"; case TaskType.LaundryService: return "Handle laundry service"; default: return "General hotel task"; } } #endregion #region Event Handlers private void OnStaffHiredHandler(Staff staff) { if (!allStaff.Contains(staff)) { allStaff.Add(staff); if (staffByType.ContainsKey(staff.Type)) { staffByType[staff.Type].Add(staff); } } OnStaffHired?.Invoke(staff); } private void OnStaffCompleteTaskHandler(Staff staff) { // Handle task completion effects Debug.Log($"{staff.StaffName} completed a task"); } private void OnTaskAssignedHandler(Staff staff, StaffTask task) { Debug.Log($"Task {task.taskType} assigned to {staff.StaffName}"); } private void OnGuestArrived(Guest guest) { // Create check-in task for arriving guests CreateTask(TaskType.CheckInGuest, guest.transform.position, guest.gameObject, null, 6); } #endregion #region Statistics and Information public int GetTotalStaffCount() { return allStaff.Count; } public float GetTotalDailyWages() { return allStaff.Count * dailyWageCost; } public Dictionary GetStaffCountByType() { Dictionary counts = new Dictionary(); foreach (var kvp in staffByType) { counts[kvp.Key] = kvp.Value.Count; } return counts; } public List GetBusiestStaff() { return allStaff.OrderByDescending(s => s.TaskCount).Take(5).ToList(); } public float GetAverageStaffEfficiency() { if (allStaff.Count == 0) return 0f; return allStaff.Average(s => s.Efficiency); } #endregion #region Debug and Visualization private void OnDrawGizmosSelected() { if (staffSpawnPoint != null) { Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(staffSpawnPoint.position, 1f); Gizmos.DrawWireCube(staffSpawnPoint.position + Vector3.up, Vector3.one * 0.8f); } } #endregion }