using UnityEngine; using System.Collections.Generic; using System.Linq; public class FacilityManager : MonoBehaviour { public static FacilityManager Instance { get; private set; } [Header("Available Facilities")] [SerializeField] private List hotelFacilities = new List(); [Header("Facility Prefabs")] [SerializeField] private GameObject restaurantPrefab; [SerializeField] private GameObject barPrefab; [SerializeField] private GameObject gymPrefab; [SerializeField] private GameObject playAreaPrefab; [SerializeField] private GameObject valetStationPrefab; // Events public System.Action OnFacilityAdded; public System.Action OnFacilityRemoved; public System.Action OnFacilityUsed; private void Awake() { if (Instance != null && Instance != this) { Destroy(this.gameObject); return; } Instance = this; } private void Start() { InitializeFacilities(); } #region Initialization private void InitializeFacilities() { // Find existing facilities in the scene Facility[] existingFacilities = FindObjectsOfType(); foreach (Facility facility in existingFacilities) { if (!hotelFacilities.Contains(facility)) { hotelFacilities.Add(facility); } } Debug.Log($"Initialized with {hotelFacilities.Count} facilities"); } #endregion #region Facility Management public bool AddFacility(FacilityType facilityType, Vector3 position, Room associatedRoom = null) { GameObject facilityPrefab = GetFacilityPrefab(facilityType); if (facilityPrefab == null) { facilityPrefab = CreateDefaultFacilityPrefab(facilityType); } GameObject facilityObj = Instantiate(facilityPrefab, position, Quaternion.identity); Facility facility = facilityObj.GetComponent(); if (facility == null) { facility = facilityObj.AddComponent(); } // Configure facility facility.Initialize(facilityType, associatedRoom); hotelFacilities.Add(facility); OnFacilityAdded?.Invoke(facility); Debug.Log($"Added facility: {facilityType} at {position}"); return true; } public bool RemoveFacility(Facility facility) { if (facility == null || !hotelFacilities.Contains(facility)) { return false; } hotelFacilities.Remove(facility); OnFacilityRemoved?.Invoke(facility); Destroy(facility.gameObject); Debug.Log($"Removed facility: {facility.Type}"); return true; } private GameObject GetFacilityPrefab(FacilityType facilityType) { switch (facilityType) { case FacilityType.Restaurant: return restaurantPrefab; case FacilityType.Bar: return barPrefab; case FacilityType.Gym: return gymPrefab; case FacilityType.PlayArea: return playAreaPrefab; case FacilityType.ValetParking: return valetStationPrefab; default: return null; } } private GameObject CreateDefaultFacilityPrefab(FacilityType facilityType) { GameObject facility = GameObject.CreatePrimitive(PrimitiveType.Cube); facility.name = facilityType.ToString(); facility.transform.localScale = new Vector3(2f, 1f, 2f); // Set color based on facility type Color facilityColor = GetFacilityColor(facilityType); facility.GetComponent().material.color = facilityColor; return facility; } private Color GetFacilityColor(FacilityType facilityType) { switch (facilityType) { case FacilityType.Restaurant: return Color.red; case FacilityType.Bar: return new Color(0.5f, 0.2f, 0f); // Brown case FacilityType.Gym: return Color.yellow; case FacilityType.PlayArea: return Color.green; case FacilityType.ValetParking: return Color.blue; case FacilityType.Spa: return Color.magenta; case FacilityType.BusinessCenter: return Color.gray; case FacilityType.LaundryService: return Color.white; default: return Color.gray; } } #endregion #region Facility Queries public List GetFacilitiesByType(FacilityType facilityType) { return hotelFacilities.Where(f => f.Type == facilityType).ToList(); } public List GetAvailableFacilities() { return hotelFacilities.Where(f => f.IsOperational).ToList(); } public Facility GetNearestFacility(Vector3 position, FacilityType facilityType) { var facilitiesOfType = GetFacilitiesByType(facilityType); return facilitiesOfType .Where(f => f.IsOperational) .OrderBy(f => Vector3.Distance(f.transform.position, position)) .FirstOrDefault(); } public bool HasFacility(FacilityType facilityType) { return GetFacilitiesByType(facilityType).Any(f => f.IsOperational); } public float GetFacilitySatisfactionRating(FacilityType facilityType) { var facilities = GetFacilitiesByType(facilityType); if (facilities.Count == 0) return 0f; return facilities.Average(f => f.QualityRating); } #endregion #region Wish Fulfillment public bool CanFulfillWish(WishType wishType) { FacilityType requiredFacility = GetRequiredFacilityForWish(wishType); return HasFacility(requiredFacility); } public Facility FindFacilityForWish(WishType wishType, Vector3 guestPosition) { FacilityType requiredFacility = GetRequiredFacilityForWish(wishType); return GetNearestFacility(guestPosition, requiredFacility); } private FacilityType GetRequiredFacilityForWish(WishType wishType) { switch (wishType) { case WishType.Restaurant: return FacilityType.Restaurant; case WishType.BarService: return FacilityType.Bar; case WishType.PlayArea: return FacilityType.PlayArea; case WishType.ValetParking: return FacilityType.ValetParking; case WishType.WashingService: case WishType.CleaningService: return FacilityType.LaundryService; case WishType.ActivityPlanning: return FacilityType.BusinessCenter; case WishType.RoomService: return FacilityType.Restaurant; // Room service originates from restaurant default: return FacilityType.None; } } public float CalculateWishFulfillmentBonus(Guest guest) { if (guest?.Wishes == null) return 0f; float totalBonus = 0f; int fulfilledWishes = 0; foreach (var wish in guest.Wishes) { if (CanFulfillWish(wish.wishType)) { totalBonus += wish.importance; fulfilledWishes++; } } // Bonus scales with the percentage of wishes that can be fulfilled float fulfillmentRate = guest.Wishes.Count > 0 ? (float)fulfilledWishes / guest.Wishes.Count : 0f; return totalBonus * fulfillmentRate; } #endregion #region Statistics and Information public List GetAllFacilities() { return new List(hotelFacilities); } public int GetFacilityCount(FacilityType facilityType) { return GetFacilitiesByType(facilityType).Count; } public Dictionary GetFacilityCountByType() { Dictionary counts = new Dictionary(); foreach (FacilityType type in System.Enum.GetValues(typeof(FacilityType))) { counts[type] = GetFacilityCount(type); } return counts; } public float GetOverallFacilityRating() { if (hotelFacilities.Count == 0) return 0f; return hotelFacilities.Average(f => f.QualityRating); } #endregion } // Facility Component public class Facility : MonoBehaviour { [Header("Facility Info")] [SerializeField] private FacilityType facilityType = FacilityType.None; [SerializeField] private string facilityName; [SerializeField] private bool isOperational = true; [Header("Quality and Capacity")] [SerializeField] private float qualityRating = 0.7f; // 0 to 1 [SerializeField] private int maxCapacity = 10; [SerializeField] private List currentUsers = new List(); [Header("Associated Room")] [SerializeField] private Room associatedRoom; [Header("Staff Requirements")] [SerializeField] private List requiredStaffTypes = new List(); [SerializeField] private int minStaffCount = 1; // Events public System.Action OnGuestUseFacility; public System.Action OnGuestLeaveFacility; #region Properties public FacilityType Type => facilityType; public string FacilityName => string.IsNullOrEmpty(facilityName) ? facilityType.ToString() : facilityName; public bool IsOperational => isOperational && HasRequiredStaff(); public float QualityRating => qualityRating; public int CurrentCapacity => currentUsers.Count; public int MaxCapacity => maxCapacity; public bool HasCapacity => CurrentCapacity < MaxCapacity; public Room AssociatedRoom => associatedRoom; #endregion public void Initialize(FacilityType type, Room room = null) { facilityType = type; associatedRoom = room; SetupFacilityDefaults(); Debug.Log($"Initialized facility: {FacilityName}"); } private void SetupFacilityDefaults() { switch (facilityType) { case FacilityType.Restaurant: maxCapacity = 20; requiredStaffTypes.Add(Staff.StaffType.Chef); break; case FacilityType.Bar: maxCapacity = 15; requiredStaffTypes.Add(Staff.StaffType.Chef); // Bartender would be ideal, but using chef for now break; case FacilityType.PlayArea: maxCapacity = 30; break; case FacilityType.ValetParking: maxCapacity = 50; requiredStaffTypes.Add(Staff.StaffType.Valet); break; case FacilityType.LaundryService: maxCapacity = 5; requiredStaffTypes.Add(Staff.StaffType.Housekeeper); break; } } #region Guest Interaction public bool CanGuestUseFacility(Guest guest) { if (!IsOperational || !HasCapacity) return false; // Check if guest has specific requirements for this facility return true; } public bool AddGuest(Guest guest) { if (!CanGuestUseFacility(guest)) return false; currentUsers.Add(guest); OnGuestUseFacility?.Invoke(guest); Debug.Log($"Guest {guest.GuestName} is now using {FacilityName}"); return true; } public bool RemoveGuest(Guest guest) { if (!currentUsers.Contains(guest)) return false; currentUsers.Remove(guest); OnGuestLeaveFacility?.Invoke(guest); Debug.Log($"Guest {guest.GuestName} has left {FacilityName}"); return true; } #endregion #region Staff Management private bool HasRequiredStaff() { if (requiredStaffTypes.Count == 0) return true; if (StaffManager.Instance == null) return false; foreach (var staffType in requiredStaffTypes) { if (StaffManager.Instance.GetStaffCount(staffType) < minStaffCount) return false; } return true; } public List GetRequiredStaffTypes() { return new List(requiredStaffTypes); } #endregion #region Facility Management public void SetOperational(bool operational) { isOperational = operational; if (!operational) { // Remove all current users var usersToRemove = new List(currentUsers); foreach (var guest in usersToRemove) { RemoveGuest(guest); } } Debug.Log($"{FacilityName} is now {(operational ? "operational" : "closed")}"); } public void UpgradeQuality(float qualityIncrease) { qualityRating = Mathf.Clamp01(qualityRating + qualityIncrease); Debug.Log($"{FacilityName} quality upgraded to {qualityRating:P0}"); } public void IncreaseCapacity(int capacityIncrease) { maxCapacity += capacityIncrease; Debug.Log($"{FacilityName} capacity increased to {maxCapacity}"); } #endregion private void OnMouseDown() { // Show facility info when clicked Debug.Log($"Facility: {FacilityName}\nType: {facilityType}\nOperational: {IsOperational}\nCapacity: {CurrentCapacity}/{MaxCapacity}\nQuality: {qualityRating:P0}"); } private void OnDrawGizmosSelected() { // Draw facility area Gizmos.color = GetFacilityColor(); Gizmos.DrawWireCube(transform.position, transform.localScale); // Draw capacity indicator Gizmos.color = Color.white; for (int i = 0; i < CurrentCapacity && i < 10; i++) { Vector3 userPos = transform.position + Vector3.up * (i * 0.5f + 1f); Gizmos.DrawWireSphere(userPos, 0.2f); } } private Color GetFacilityColor() { if (!IsOperational) return Color.gray; switch (facilityType) { case FacilityType.Restaurant: return Color.red; case FacilityType.Bar: return new Color(0.5f, 0.2f, 0f); case FacilityType.PlayArea: return Color.green; case FacilityType.ValetParking: return Color.blue; default: return Color.yellow; } } } // Enumerations public enum FacilityType { None, Restaurant, Bar, Gym, PlayArea, ValetParking, Spa, BusinessCenter, LaundryService, Pool, ConferenceRoom }