| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- using UnityEngine;
- using UnityEngine.AI;
- using System.Collections.Generic;
- using System;
- [RequireComponent(typeof(NavMeshAgent))]
- public class Guest : MonoBehaviour
- {
- [Header("Guest Info")]
- [SerializeField] private string guestName;
- [SerializeField] private GuestType guestType = GuestType.Regular;
- [SerializeField] private int stayDuration = 3; // days
- [Header("Movement")]
- [SerializeField] private float walkSpeed = 3.5f;
- [SerializeField] private float runSpeed = 6f;
- [Header("Mood Visualization")]
- [SerializeField] private GameObject moodIcon;
- [SerializeField] private SpriteRenderer moodRenderer;
- [SerializeField] private Sprite[] moodSprites; // Happy, Neutral, Annoyed, Angry
- private NavMeshAgent agent;
- private GuestState currentState = GuestState.Arriving;
- private GuestMood currentMood = GuestMood.Neutral;
- private List<GuestWish> wishes = new List<GuestWish>();
- private List<string> moodReasons = new List<string>();
- private Room assignedRoom;
- private Vector3 spawnPosition;
- private float satisfactionLevel = 0.5f; // 0 to 1
- private float patience = 100f;
- private float maxPatience = 100f;
- // Navigation targets
- private Vector3 currentDestination;
- private bool hasDestination = false;
- // Events
- public static event Action<Guest> OnGuestArrived;
- public static event Action<Guest> OnGuestLeft;
- public static event Action<Guest> OnGuestAssignedRoom;
- public enum GuestState
- {
- Arriving,
- LookingForReception,
- CheckingIn,
- GoingToRoom,
- InRoom,
- Exploring,
- Leaving,
- Left
- }
- public enum GuestMood
- {
- Happy = 0,
- Neutral = 1,
- Annoyed = 2,
- Angry = 3
- }
- public enum GuestType
- {
- Regular,
- Business,
- Family,
- VIP,
- Celebrity
- }
- #region Properties
- public string GuestName
- {
- get => string.IsNullOrEmpty(guestName) ? GenerateRandomName() : guestName;
- set => guestName = value;
- }
- public GuestState CurrentState => currentState;
- public GuestMood CurrentMood => currentMood;
- public GuestType Type => guestType;
- public float SatisfactionLevel => satisfactionLevel;
- public float Patience => patience;
- public List<GuestWish> Wishes => wishes;
- public List<string> MoodReasons => moodReasons;
- public Room AssignedRoom => assignedRoom;
- #endregion
- private void Awake()
- {
- agent = GetComponent<NavMeshAgent>();
- agent.speed = walkSpeed;
- SetupMoodIcon();
- GenerateWishes();
- spawnPosition = transform.position;
- }
- private void Start()
- {
- SetState(GuestState.Arriving);
- OnGuestArrived?.Invoke(this);
- // Look for reception to check in
- FindAndGoToReception();
- }
- private void Update()
- {
- UpdatePatience();
- UpdateBehaviorBasedOnState();
- UpdateMoodDisplay();
- // Check if agent reached destination
- if (hasDestination && agent.enabled && !agent.pathPending && agent.remainingDistance < 0.5f)
- {
- OnReachedDestination();
- }
- }
- #region State Management
- private void SetState(GuestState newState)
- {
- currentState = newState;
- Debug.Log($"Guest {GuestName} state changed to: {newState}");
- switch (newState)
- {
- case GuestState.Arriving:
- AddMoodReason("Just arrived at the hotel");
- break;
- case GuestState.LookingForReception:
- AddMoodReason("Looking for reception desk");
- break;
- case GuestState.CheckingIn:
- AddMoodReason("Checking into the hotel");
- break;
- case GuestState.GoingToRoom:
- AddMoodReason("Heading to assigned room");
- break;
- case GuestState.InRoom:
- AddMoodReason("Settling into room");
- break;
- case GuestState.Exploring:
- AddMoodReason("Exploring hotel facilities");
- break;
- case GuestState.Leaving:
- AddMoodReason("Checking out and leaving");
- break;
- }
- }
- private void UpdateBehaviorBasedOnState()
- {
- switch (currentState)
- {
- case GuestState.LookingForReception:
- if (!hasDestination)
- {
- FindAndGoToReception();
- }
- break;
- case GuestState.CheckingIn:
- // Stay at reception for a moment
- if (Time.time % 5f < 0.1f) // Every 5 seconds, try to get a room
- {
- TryGetRoom();
- }
- break;
- case GuestState.InRoom:
- // Randomly decide to explore or stay
- if (UnityEngine.Random.value < 0.001f) // Small chance per frame
- {
- DecideNextActivity();
- }
- break;
- }
- }
- private void UpdatePatience()
- {
- if (currentState == GuestState.LookingForReception ||
- currentState == GuestState.CheckingIn)
- {
- patience -= Time.deltaTime * 2f; // Lose patience while waiting
- if (patience <= 0)
- {
- SetMood(GuestMood.Angry);
- AddMoodReason("Waited too long without service");
- LeaveHotel();
- }
- else if (patience < maxPatience * 0.3f)
- {
- SetMood(GuestMood.Annoyed);
- AddMoodReason("Taking too long to check in");
- }
- }
- }
- #endregion
- #region Navigation
- public bool MoveTo(Vector3 destination)
- {
- if (!agent.enabled) return false;
- agent.SetDestination(destination);
- currentDestination = destination;
- hasDestination = true;
- return true;
- }
- private void OnReachedDestination()
- {
- hasDestination = false;
- switch (currentState)
- {
- case GuestState.LookingForReception:
- SetState(GuestState.CheckingIn);
- break;
- case GuestState.GoingToRoom:
- SetState(GuestState.InRoom);
- AddMoodReason("Arrived at assigned room");
- break;
- }
- }
- private void FindAndGoToReception()
- {
- // Look for reception room or reception desk
- GameObject[] receptions = GameObject.FindGameObjectsWithTag("Reception");
- if (receptions.Length > 0)
- {
- MoveTo(receptions[0].transform.position);
- SetState(GuestState.LookingForReception);
- }
- else
- {
- // No reception found - get annoyed
- SetMood(GuestMood.Annoyed);
- AddMoodReason("Cannot find hotel reception");
- // Wander around looking for it
- WanderRandomly();
- }
- }
- private void WanderRandomly()
- {
- Vector3 randomDirection = UnityEngine.Random.insideUnitSphere * 10f;
- randomDirection += transform.position;
- randomDirection.y = transform.position.y;
- if (NavMesh.SamplePosition(randomDirection, out NavMeshHit hit, 10f, NavMesh.AllAreas))
- {
- MoveTo(hit.position);
- }
- }
- #endregion
- #region Room Management
- private void TryGetRoom()
- {
- // Try to get a room assignment from hotel manager
- Room availableRoom = HotelManager.Instance?.GetAvailableRoom(this);
- if (availableRoom != null)
- {
- AssignRoom(availableRoom);
- }
- else
- {
- // No rooms available
- SetMood(GuestMood.Annoyed);
- AddMoodReason("No rooms available");
- // Lose more patience
- patience -= 20f;
- if (patience <= 20f)
- {
- LeaveHotel();
- }
- }
- }
- public void AssignRoom(Room room)
- {
- assignedRoom = room;
- SetState(GuestState.GoingToRoom);
- // Calculate room satisfaction
- float roomSatisfaction = CalculateRoomSatisfaction(room);
- satisfactionLevel = Mathf.Clamp01(satisfactionLevel + roomSatisfaction - 0.5f);
- if (roomSatisfaction > 0.7f)
- {
- SetMood(GuestMood.Happy);
- AddMoodReason("Very satisfied with the room");
- }
- else if (roomSatisfaction < 0.3f)
- {
- SetMood(GuestMood.Annoyed);
- AddMoodReason("Room doesn't meet expectations");
- }
- // Go to room
- MoveTo(room.roomPoints[0]); // Go to room center
- OnGuestAssignedRoom?.Invoke(this);
- }
- private float CalculateRoomSatisfaction(Room room)
- {
- float satisfaction = 0.5f; // Base satisfaction
- // Check if room type matches guest preferences
- // This would be expanded based on guest type and wishes
- return satisfaction;
- }
- private void DecideNextActivity()
- {
- // Based on wishes, decide what to do next
- if (wishes.Count > 0)
- {
- GuestWish randomWish = wishes[UnityEngine.Random.Range(0, wishes.Count)];
- if (TryFulfillWish(randomWish))
- {
- SetState(GuestState.Exploring);
- }
- }
- else
- {
- // No specific wishes, just wander
- WanderRandomly();
- SetState(GuestState.Exploring);
- }
- }
- private bool TryFulfillWish(GuestWish wish)
- {
- // Look for facilities that can fulfill the wish
- // This would be expanded with actual facility finding logic
- return false;
- }
- #endregion
- #region Mood System
- private void SetMood(GuestMood mood)
- {
- currentMood = mood;
- UpdateMoodDisplay();
- }
- private void AddMoodReason(string reason)
- {
- moodReasons.Insert(0, $"{DateTime.Now:HH:mm} - {reason}");
- // Keep only recent reasons
- if (moodReasons.Count > 10)
- {
- moodReasons.RemoveAt(moodReasons.Count - 1);
- }
- }
- private void UpdateMoodDisplay()
- {
- if (moodRenderer != null && moodSprites != null && moodSprites.Length > (int)currentMood)
- {
- moodRenderer.sprite = moodSprites[(int)currentMood];
- // Show mood icon only if not neutral or happy
- moodIcon.SetActive(currentMood != GuestMood.Neutral && currentMood != GuestMood.Happy);
- }
- }
- private void SetupMoodIcon()
- {
- if (moodIcon == null)
- {
- moodIcon = new GameObject("Mood Icon");
- moodIcon.transform.SetParent(transform);
- moodIcon.transform.localPosition = Vector3.up * 2.5f;
- moodRenderer = moodIcon.AddComponent<SpriteRenderer>();
- moodRenderer.sortingOrder = 10;
- moodIcon.SetActive(false);
- }
- }
- #endregion
- #region Wish System
- private void GenerateWishes()
- {
- wishes.Clear();
- // Generate wishes based on guest type
- int wishCount = UnityEngine.Random.Range(1, 4);
- List<WishType> availableWishes = new List<WishType>((WishType[])Enum.GetValues(typeof(WishType)));
- for (int i = 0; i < wishCount && availableWishes.Count > 0; i++)
- {
- int randomIndex = UnityEngine.Random.Range(0, availableWishes.Count);
- WishType wishType = availableWishes[randomIndex];
- availableWishes.RemoveAt(randomIndex);
- wishes.Add(new GuestWish
- {
- wishType = wishType,
- importance = GetWishImportanceForGuestType(wishType),
- isFulfilled = false
- });
- }
- }
- private float GetWishImportanceForGuestType(WishType wishType)
- {
- // Different guest types value different wishes
- switch (guestType)
- {
- case GuestType.Business:
- return wishType == WishType.RoomService || wishType == WishType.CleaningService ? 0.9f : 0.5f;
- case GuestType.Family:
- return wishType == WishType.PlayArea || wishType == WishType.Restaurant ? 0.8f : 0.5f;
- case GuestType.VIP:
- return wishType == WishType.ValetParking || wishType == WishType.ActivityPlanning ? 0.9f : 0.6f;
- default:
- return 0.5f;
- }
- }
- #endregion
- #region Utility Methods
- private string GenerateRandomName()
- {
- string[] firstNames = { "John", "Jane", "Mike", "Sarah", "David", "Lisa", "Chris", "Amy", "Tom", "Kate" };
- string[] lastNames = { "Smith", "Johnson", "Brown", "Davis", "Wilson", "Miller", "Moore", "Taylor", "Anderson", "Thomas" };
- return $"{firstNames[UnityEngine.Random.Range(0, firstNames.Length)]} {lastNames[UnityEngine.Random.Range(0, lastNames.Length)]}";
- }
- public void LeaveHotel()
- {
- SetState(GuestState.Leaving);
- MoveTo(spawnPosition); // Go back to entrance
- OnGuestLeft?.Invoke(this);
- // Destroy after a delay
- Destroy(gameObject, 3f);
- }
- private void OnMouseDown()
- {
- // Show guest info when clicked
- if (GuestInfoUI.Instance != null)
- {
- GuestInfoUI.Instance.ShowGuestInfo(this);
- }
- }
- #endregion
- }
- // Supporting classes
- [System.Serializable]
- public class GuestWish
- {
- public WishType wishType;
- public float importance; // 0 to 1
- public bool isFulfilled;
- }
- public enum WishType
- {
- Restaurant,
- ValetParking,
- ActivityPlanning,
- RoomService,
- BarService,
- PlayArea,
- CleaningService,
- WashingService,
- CloseToEvents
- }
|