FacilityManager.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. public class FacilityManager : MonoBehaviour
  5. {
  6. public static FacilityManager Instance { get; private set; }
  7. [Header("Available Facilities")]
  8. [SerializeField] private List<Facility> hotelFacilities = new List<Facility>();
  9. [Header("Facility Prefabs")]
  10. [SerializeField] private GameObject restaurantPrefab;
  11. [SerializeField] private GameObject barPrefab;
  12. [SerializeField] private GameObject gymPrefab;
  13. [SerializeField] private GameObject playAreaPrefab;
  14. [SerializeField] private GameObject valetStationPrefab;
  15. // Events
  16. public System.Action<Facility> OnFacilityAdded;
  17. public System.Action<Facility> OnFacilityRemoved;
  18. public System.Action<Guest, Facility> OnFacilityUsed;
  19. private void Awake()
  20. {
  21. if (Instance != null && Instance != this)
  22. {
  23. Destroy(this.gameObject);
  24. return;
  25. }
  26. Instance = this;
  27. }
  28. private void Start()
  29. {
  30. InitializeFacilities();
  31. }
  32. #region Initialization
  33. private void InitializeFacilities()
  34. {
  35. // Find existing facilities in the scene
  36. Facility[] existingFacilities = FindObjectsOfType<Facility>();
  37. foreach (Facility facility in existingFacilities)
  38. {
  39. if (!hotelFacilities.Contains(facility))
  40. {
  41. hotelFacilities.Add(facility);
  42. }
  43. }
  44. Debug.Log($"Initialized with {hotelFacilities.Count} facilities");
  45. }
  46. #endregion
  47. #region Facility Management
  48. public bool AddFacility(FacilityType facilityType, Vector3 position, Room associatedRoom = null)
  49. {
  50. GameObject facilityPrefab = GetFacilityPrefab(facilityType);
  51. if (facilityPrefab == null)
  52. {
  53. facilityPrefab = CreateDefaultFacilityPrefab(facilityType);
  54. }
  55. GameObject facilityObj = Instantiate(facilityPrefab, position, Quaternion.identity);
  56. Facility facility = facilityObj.GetComponent<Facility>();
  57. if (facility == null)
  58. {
  59. facility = facilityObj.AddComponent<Facility>();
  60. }
  61. // Configure facility
  62. facility.Initialize(facilityType, associatedRoom);
  63. hotelFacilities.Add(facility);
  64. OnFacilityAdded?.Invoke(facility);
  65. Debug.Log($"Added facility: {facilityType} at {position}");
  66. return true;
  67. }
  68. public bool RemoveFacility(Facility facility)
  69. {
  70. if (facility == null || !hotelFacilities.Contains(facility))
  71. {
  72. return false;
  73. }
  74. hotelFacilities.Remove(facility);
  75. OnFacilityRemoved?.Invoke(facility);
  76. Destroy(facility.gameObject);
  77. Debug.Log($"Removed facility: {facility.Type}");
  78. return true;
  79. }
  80. private GameObject GetFacilityPrefab(FacilityType facilityType)
  81. {
  82. switch (facilityType)
  83. {
  84. case FacilityType.Restaurant:
  85. return restaurantPrefab;
  86. case FacilityType.Bar:
  87. return barPrefab;
  88. case FacilityType.Gym:
  89. return gymPrefab;
  90. case FacilityType.PlayArea:
  91. return playAreaPrefab;
  92. case FacilityType.ValetParking:
  93. return valetStationPrefab;
  94. default:
  95. return null;
  96. }
  97. }
  98. private GameObject CreateDefaultFacilityPrefab(FacilityType facilityType)
  99. {
  100. GameObject facility = GameObject.CreatePrimitive(PrimitiveType.Cube);
  101. facility.name = facilityType.ToString();
  102. facility.transform.localScale = new Vector3(2f, 1f, 2f);
  103. // Set color based on facility type
  104. Color facilityColor = GetFacilityColor(facilityType);
  105. facility.GetComponent<Renderer>().material.color = facilityColor;
  106. return facility;
  107. }
  108. private Color GetFacilityColor(FacilityType facilityType)
  109. {
  110. switch (facilityType)
  111. {
  112. case FacilityType.Restaurant: return Color.red;
  113. case FacilityType.Bar: return new Color(0.5f, 0.2f, 0f); // Brown
  114. case FacilityType.Gym: return Color.yellow;
  115. case FacilityType.PlayArea: return Color.green;
  116. case FacilityType.ValetParking: return Color.blue;
  117. case FacilityType.Spa: return Color.magenta;
  118. case FacilityType.BusinessCenter: return Color.gray;
  119. case FacilityType.LaundryService: return Color.white;
  120. default: return Color.gray;
  121. }
  122. }
  123. #endregion
  124. #region Facility Queries
  125. public List<Facility> GetFacilitiesByType(FacilityType facilityType)
  126. {
  127. return hotelFacilities.Where(f => f.Type == facilityType).ToList();
  128. }
  129. public List<Facility> GetAvailableFacilities()
  130. {
  131. return hotelFacilities.Where(f => f.IsOperational).ToList();
  132. }
  133. public Facility GetNearestFacility(Vector3 position, FacilityType facilityType)
  134. {
  135. var facilitiesOfType = GetFacilitiesByType(facilityType);
  136. return facilitiesOfType
  137. .Where(f => f.IsOperational)
  138. .OrderBy(f => Vector3.Distance(f.transform.position, position))
  139. .FirstOrDefault();
  140. }
  141. public bool HasFacility(FacilityType facilityType)
  142. {
  143. return GetFacilitiesByType(facilityType).Any(f => f.IsOperational);
  144. }
  145. public float GetFacilitySatisfactionRating(FacilityType facilityType)
  146. {
  147. var facilities = GetFacilitiesByType(facilityType);
  148. if (facilities.Count == 0) return 0f;
  149. return facilities.Average(f => f.QualityRating);
  150. }
  151. #endregion
  152. #region Wish Fulfillment
  153. public bool CanFulfillWish(WishType wishType)
  154. {
  155. FacilityType requiredFacility = GetRequiredFacilityForWish(wishType);
  156. return HasFacility(requiredFacility);
  157. }
  158. public Facility FindFacilityForWish(WishType wishType, Vector3 guestPosition)
  159. {
  160. FacilityType requiredFacility = GetRequiredFacilityForWish(wishType);
  161. return GetNearestFacility(guestPosition, requiredFacility);
  162. }
  163. private FacilityType GetRequiredFacilityForWish(WishType wishType)
  164. {
  165. switch (wishType)
  166. {
  167. case WishType.Restaurant:
  168. return FacilityType.Restaurant;
  169. case WishType.BarService:
  170. return FacilityType.Bar;
  171. case WishType.PlayArea:
  172. return FacilityType.PlayArea;
  173. case WishType.ValetParking:
  174. return FacilityType.ValetParking;
  175. case WishType.WashingService:
  176. case WishType.CleaningService:
  177. return FacilityType.LaundryService;
  178. case WishType.ActivityPlanning:
  179. return FacilityType.BusinessCenter;
  180. case WishType.RoomService:
  181. return FacilityType.Restaurant; // Room service originates from restaurant
  182. default:
  183. return FacilityType.None;
  184. }
  185. }
  186. public float CalculateWishFulfillmentBonus(Guest guest)
  187. {
  188. if (guest?.Wishes == null) return 0f;
  189. float totalBonus = 0f;
  190. int fulfilledWishes = 0;
  191. foreach (var wish in guest.Wishes)
  192. {
  193. if (CanFulfillWish(wish.wishType))
  194. {
  195. totalBonus += wish.importance;
  196. fulfilledWishes++;
  197. }
  198. }
  199. // Bonus scales with the percentage of wishes that can be fulfilled
  200. float fulfillmentRate = guest.Wishes.Count > 0 ? (float)fulfilledWishes / guest.Wishes.Count : 0f;
  201. return totalBonus * fulfillmentRate;
  202. }
  203. #endregion
  204. #region Statistics and Information
  205. public List<Facility> GetAllFacilities()
  206. {
  207. return new List<Facility>(hotelFacilities);
  208. }
  209. public int GetFacilityCount(FacilityType facilityType)
  210. {
  211. return GetFacilitiesByType(facilityType).Count;
  212. }
  213. public Dictionary<FacilityType, int> GetFacilityCountByType()
  214. {
  215. Dictionary<FacilityType, int> counts = new Dictionary<FacilityType, int>();
  216. foreach (FacilityType type in System.Enum.GetValues(typeof(FacilityType)))
  217. {
  218. counts[type] = GetFacilityCount(type);
  219. }
  220. return counts;
  221. }
  222. public float GetOverallFacilityRating()
  223. {
  224. if (hotelFacilities.Count == 0) return 0f;
  225. return hotelFacilities.Average(f => f.QualityRating);
  226. }
  227. #endregion
  228. }
  229. // Facility Component
  230. public class Facility : MonoBehaviour
  231. {
  232. [Header("Facility Info")]
  233. [SerializeField] private FacilityType facilityType = FacilityType.None;
  234. [SerializeField] private string facilityName;
  235. [SerializeField] private bool isOperational = true;
  236. [Header("Quality and Capacity")]
  237. [SerializeField] private float qualityRating = 0.7f; // 0 to 1
  238. [SerializeField] private int maxCapacity = 10;
  239. [SerializeField] private List<Guest> currentUsers = new List<Guest>();
  240. [Header("Associated Room")]
  241. [SerializeField] private Room associatedRoom;
  242. [Header("Staff Requirements")]
  243. [SerializeField] private List<Staff.StaffType> requiredStaffTypes = new List<Staff.StaffType>();
  244. [SerializeField] private int minStaffCount = 1;
  245. // Events
  246. public System.Action<Guest> OnGuestUseFacility;
  247. public System.Action<Guest> OnGuestLeaveFacility;
  248. #region Properties
  249. public FacilityType Type => facilityType;
  250. public string FacilityName => string.IsNullOrEmpty(facilityName) ? facilityType.ToString() : facilityName;
  251. public bool IsOperational => isOperational && HasRequiredStaff();
  252. public float QualityRating => qualityRating;
  253. public int CurrentCapacity => currentUsers.Count;
  254. public int MaxCapacity => maxCapacity;
  255. public bool HasCapacity => CurrentCapacity < MaxCapacity;
  256. public Room AssociatedRoom => associatedRoom;
  257. #endregion
  258. public void Initialize(FacilityType type, Room room = null)
  259. {
  260. facilityType = type;
  261. associatedRoom = room;
  262. SetupFacilityDefaults();
  263. Debug.Log($"Initialized facility: {FacilityName}");
  264. }
  265. private void SetupFacilityDefaults()
  266. {
  267. switch (facilityType)
  268. {
  269. case FacilityType.Restaurant:
  270. maxCapacity = 20;
  271. requiredStaffTypes.Add(Staff.StaffType.Chef);
  272. break;
  273. case FacilityType.Bar:
  274. maxCapacity = 15;
  275. requiredStaffTypes.Add(Staff.StaffType.Chef); // Bartender would be ideal, but using chef for now
  276. break;
  277. case FacilityType.PlayArea:
  278. maxCapacity = 30;
  279. break;
  280. case FacilityType.ValetParking:
  281. maxCapacity = 50;
  282. requiredStaffTypes.Add(Staff.StaffType.Valet);
  283. break;
  284. case FacilityType.LaundryService:
  285. maxCapacity = 5;
  286. requiredStaffTypes.Add(Staff.StaffType.Housekeeper);
  287. break;
  288. }
  289. }
  290. #region Guest Interaction
  291. public bool CanGuestUseFacility(Guest guest)
  292. {
  293. if (!IsOperational || !HasCapacity)
  294. return false;
  295. // Check if guest has specific requirements for this facility
  296. return true;
  297. }
  298. public bool AddGuest(Guest guest)
  299. {
  300. if (!CanGuestUseFacility(guest))
  301. return false;
  302. currentUsers.Add(guest);
  303. OnGuestUseFacility?.Invoke(guest);
  304. Debug.Log($"Guest {guest.GuestName} is now using {FacilityName}");
  305. return true;
  306. }
  307. public bool RemoveGuest(Guest guest)
  308. {
  309. if (!currentUsers.Contains(guest))
  310. return false;
  311. currentUsers.Remove(guest);
  312. OnGuestLeaveFacility?.Invoke(guest);
  313. Debug.Log($"Guest {guest.GuestName} has left {FacilityName}");
  314. return true;
  315. }
  316. #endregion
  317. #region Staff Management
  318. private bool HasRequiredStaff()
  319. {
  320. if (requiredStaffTypes.Count == 0)
  321. return true;
  322. if (StaffManager.Instance == null)
  323. return false;
  324. foreach (var staffType in requiredStaffTypes)
  325. {
  326. if (StaffManager.Instance.GetStaffCount(staffType) < minStaffCount)
  327. return false;
  328. }
  329. return true;
  330. }
  331. public List<Staff.StaffType> GetRequiredStaffTypes()
  332. {
  333. return new List<Staff.StaffType>(requiredStaffTypes);
  334. }
  335. #endregion
  336. #region Facility Management
  337. public void SetOperational(bool operational)
  338. {
  339. isOperational = operational;
  340. if (!operational)
  341. {
  342. // Remove all current users
  343. var usersToRemove = new List<Guest>(currentUsers);
  344. foreach (var guest in usersToRemove)
  345. {
  346. RemoveGuest(guest);
  347. }
  348. }
  349. Debug.Log($"{FacilityName} is now {(operational ? "operational" : "closed")}");
  350. }
  351. public void UpgradeQuality(float qualityIncrease)
  352. {
  353. qualityRating = Mathf.Clamp01(qualityRating + qualityIncrease);
  354. Debug.Log($"{FacilityName} quality upgraded to {qualityRating:P0}");
  355. }
  356. public void IncreaseCapacity(int capacityIncrease)
  357. {
  358. maxCapacity += capacityIncrease;
  359. Debug.Log($"{FacilityName} capacity increased to {maxCapacity}");
  360. }
  361. #endregion
  362. private void OnMouseDown()
  363. {
  364. // Show facility info when clicked
  365. Debug.Log($"Facility: {FacilityName}\nType: {facilityType}\nOperational: {IsOperational}\nCapacity: {CurrentCapacity}/{MaxCapacity}\nQuality: {qualityRating:P0}");
  366. }
  367. private void OnDrawGizmosSelected()
  368. {
  369. // Draw facility area
  370. Gizmos.color = GetFacilityColor();
  371. Gizmos.DrawWireCube(transform.position, transform.localScale);
  372. // Draw capacity indicator
  373. Gizmos.color = Color.white;
  374. for (int i = 0; i < CurrentCapacity && i < 10; i++)
  375. {
  376. Vector3 userPos = transform.position + Vector3.up * (i * 0.5f + 1f);
  377. Gizmos.DrawWireSphere(userPos, 0.2f);
  378. }
  379. }
  380. private Color GetFacilityColor()
  381. {
  382. if (!IsOperational) return Color.gray;
  383. switch (facilityType)
  384. {
  385. case FacilityType.Restaurant: return Color.red;
  386. case FacilityType.Bar: return new Color(0.5f, 0.2f, 0f);
  387. case FacilityType.PlayArea: return Color.green;
  388. case FacilityType.ValetParking: return Color.blue;
  389. default: return Color.yellow;
  390. }
  391. }
  392. }
  393. // Enumerations
  394. public enum FacilityType
  395. {
  396. None,
  397. Restaurant,
  398. Bar,
  399. Gym,
  400. PlayArea,
  401. ValetParking,
  402. Spa,
  403. BusinessCenter,
  404. LaundryService,
  405. Pool,
  406. ConferenceRoom
  407. }