| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- 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<Staff> allStaff = new List<Staff>();
- [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<StaffTask> pendingTasks = new Queue<StaffTask>();
- private Dictionary<Staff.StaffType, List<Staff>> staffByType = new Dictionary<Staff.StaffType, List<Staff>>();
- // Events
- public System.Action<Staff> OnStaffHired;
- public System.Action<Staff> OnStaffFired;
- public System.Action<StaffTask> OnTaskCreated;
- public System.Action<StaffTask> 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<Staff>();
- }
- }
- 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<Staff>();
- if (staffComponent == null)
- {
- staffComponent = staffObj.AddComponent<Staff>();
- }
- // 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<UnityEngine.AI.NavMeshAgent>();
- 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<Renderer>().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<Staff> GetStaffByType(Staff.StaffType staffType)
- {
- return staffByType.ContainsKey(staffType) ? new List<Staff>(staffByType[staffType]) : new List<Staff>();
- }
- public List<Staff> GetAvailableStaff(Staff.StaffType staffType)
- {
- return GetStaffByType(staffType).Where(s => s.IsAvailable).ToList();
- }
- public List<Staff> GetAllStaff()
- {
- return new List<Staff>(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<Staff> 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<Staff.StaffType, int> GetStaffCountByType()
- {
- Dictionary<Staff.StaffType, int> counts = new Dictionary<Staff.StaffType, int>();
- foreach (var kvp in staffByType)
- {
- counts[kvp.Key] = kvp.Value.Count;
- }
- return counts;
- }
- public List<Staff> 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
- }
|