using System; using Customer; using UnityEngine; using UnityEngine.AI; using static Customer.MoodState; using Random = UnityEngine.Random; public class CustomerController : MonoBehaviour, IObjectParentHolder { private NavMeshAgent _navMeshAgent; private Vector3 _target; public SellCounter TargetCounter { get; private set; } [Header("WaitTime")] [SerializeField] private float _minWaitTime = 5.0f; [SerializeField] private float _maxWaitTime = 10.0f; [Header("BuyChace")] [SerializeField] private float _buyChance = 0.5f; [SerializeField] private float _buyChanceIncrease = 0.1f; [SerializeField] private float _buyChanceDecrease = 0.1f; [SerializeField] private Transform _objectHolder; private Object _currentObject; private float _waitTime; private CustomerVisibleController _visibleController; public MoodState State => _visibleController.GetState(); private Vector3 _exitPosition; public event Action OnCustomerLeft; private CustomerState _state = CustomerState.GoingToCounter; //enum public enum CustomerState { GoingToCounter, WaitingToBuy, Buying, WalkingToExit } private void Awake() { _navMeshAgent = GetComponent(); _visibleController = GetComponent(); _visibleController.SetState(Normal); } private void Update() { switch (_state) { case CustomerState.GoingToCounter: if (_navMeshAgent.remainingDistance <= _navMeshAgent.stoppingDistance) { OnDestinationReached(); } break; case CustomerState.WaitingToBuy: WaitToBuy(); break; case CustomerState.Buying: BuyItem(); break; case CustomerState.WalkingToExit: CheckIfReachedExit(); break; default: throw new ArgumentOutOfRangeException(); } } private void CheckIfReachedExit() { if (_navMeshAgent.remainingDistance <= _navMeshAgent.stoppingDistance) { Debug.Log("Bye :p"); CustomerManager.Instance.CustomerDies(this); Destroy(this.gameObject); } } private bool ShouldBuyItem() { //This should be a function that checks if a customer should buy an item //For example, if the item is worth 10 bucks, and the player sets the price to 20, the customer should not buy it since its too expensive //if an item is prices higher then X% of the base price, the customer should not buy it Object obj = TargetCounter.GetObject(); if (obj == null) { Debug.LogError("Counter has no object"); return false; } float price = obj.ObjectSo.basePrice; float sellPrice = TargetCounter.GetSellingPrice(); bool isBroken = obj.IsBroken; float difference = Mathf.Abs(price - sellPrice); float percentage = difference / price; //Log this for now Debug.Log("Difference: " + difference + " Percentage: " + percentage); //Random differnece between 0.1 and 0.2; float diff = Random.Range(_buyChanceDecrease, _buyChanceIncrease); var calculatedBuyChance = _buyChance; if (isBroken) { //Customer should be less likely to buy broken items calculatedBuyChance -= 0.1f; } if (percentage > calculatedBuyChance + diff) { return false; } return true; } public void SetDestination(Vector3 position) { _target = position; _navMeshAgent.SetDestination(_target); } public void SetTargetCounter(SellCounter counter) { TargetCounter = counter; float angle = Random.Range(0, 360); Vector3 offset = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)); this.SetDestination(counter.transform.position + offset); } private void BuyItem() { if (TargetCounter == null) { Debug.LogError("Customer has no target counter"); return; } if (!ShouldBuyItem()) { Debug.Log("Customer should not buy item"); this.SetDestination(_exitPosition); _state = CustomerState.WalkingToExit; _visibleController.SetState(Angry); SoundFXController.Instance.PlayVillagerAngryFX(); return; } Debug.Log("Customer bought item: " + TargetCounter.GetObject().ObjectSo.objectName + " for: " + TargetCounter.GetSellingPrice()); _visibleController.SetState(Normal); TargetCounter.SellItem(this); SoundFXController.Instance.PlayItemBoughtFX(); SoundFXController.Instance.PlayVillagerHappyFX(); this.SetDestination(_exitPosition); _state = CustomerState.WalkingToExit; OnCustomerLeft?.Invoke(TargetCounter, this); //Notify the customer manager that the customer left } private void OnDestinationReached() { //should tell the counter there is a customer waiting; Debug.Log("Customer reached destination for Counter: " + TargetCounter.name); _state = CustomerState.WaitingToBuy; _waitTime = Random.Range(_minWaitTime, _maxWaitTime); } void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(_target, 0.5f); } void WaitToBuy() { _waitTime -= Time.deltaTime; if (_waitTime <= 0) { _state = CustomerState.Buying; } } public Transform GetHolderTransform() { return _objectHolder; } public void SetObject(Object obj) { _currentObject = obj; } public Object GetObject() { return _currentObject; } public void ClearObject() { _currentObject = null; } public bool HasObject() { return _currentObject != null; } public void SetExitPosition(Vector3 position) { _exitPosition = position; } public void SetState(CustomerState state) { _state = state; } }