>

Sous Raccoon

Perk and Shop Merchant

UI and System

System

ShopMerchantManager.cs

ShopMerchantManager.cs

UI

UIShopMerchantPanel.cs

UIShopMerchantItemSlot.cs

Sous Raccoon

Manager in Project

System

Sous Raccoon

Customer System

UI and System

using SousRaccoon.Manager;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SceneManagement : MonoBehaviour
{
    public GameObject loadingCanvas;
    public Image loadBar;

    private void Start()
    {
        GameManager.instance.sceneManagement = this;
    }

    public void SelectState(string stateName)
    {
        Time.timeScale = 1.0f;
        //TODO : Loading Screen
        OnLoadingScreen($"State 0{stateName}");
    }

    public void SelectTestState()
    {
        Time.timeScale = 1.0f;
        OnLoadingScreen("ForMidterm");
    }

    public void SelectTargetScene(string stateName)
    {
        Time.timeScale = 1.0f;

        OnLoadingScreen(stateName);
    }

    public void StartNewTargetLevel(int levelIndex)
    {
        Time.timeScale = 1.0f;
        RunStageManager.instance.StartNewRunStage();
        OnLoadingScreen(GameManager.instance.GetSceneLevel(levelIndex));
    }

    public void StartSceneTutorial()
    {
        Time.timeScale = 1.0f;
        RunStageManager.instance.StartNewRunStage();
        OnLoadingScreen("Tutorial");
    }

    public void ReturnToLobby()
    {
        Time.timeScale = 1.0f;

        Cursor.visible = true;
        Cursor.lockState = CursorLockMode.None;

        OnLoadingScreen("Lobby");
    }

    public void NextWinStage(string sceneName)
    {
        Time.timeScale = 1.0f;
        SceneManager.LoadScene(sceneName);
    }

    public void RestartScene()
    {
        Time.timeScale = 1.0f;
        RunStageManager.instance.StartNewRunStage();
        OnLoadingScreen(SceneManager.GetActiveScene().name);
    }

    public void NextWinStageTest(string sceneName)
    {
        Time.timeScale = 1.0f;
        RunStageManager.instance.StartNewRunStage();
        RunStageManager.instance.daysCount = 5;
        OnLoadingScreen(sceneName);
    }

    public void QuitGame()
    {
        Application.Quit();
    }

    public void OnLoadingScreen(string sceneName)
    {
        if (loadingCanvas == null)
            SceneManager.LoadScene(sceneName);
        else
            StartCoroutine(LoadingScreenTimer(sceneName));
    }

    public IEnumerator LoadingScreenTimer(string sceneName)
    {
        if (StageManager.instance != null)
        {
            StageManager.instance.canPause = false;
        }

        if (LobbyManager.instance != null)
        {
            LobbyManager.instance.canPause = false;
        }

        AudioManager.instance.StopMusic();

        loadBar.fillAmount = 0;
        loadingCanvas.SetActive(true);

        Time.timeScale = 1;

        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName);
        asyncOperation.allowSceneActivation = false;
        float progress = 0;
        while (!asyncOperation.isDone)
        {
            progress = Mathf.MoveTowards(progress, asyncOperation.progress, Time.deltaTime);
            loadBar.fillAmount = progress;
            if (progress >= 0.9f)
            {
                loadBar.fillAmount = 1;
                asyncOperation.allowSceneActivation = true;
            }
            yield return null

using SousRaccoon.Data;
using SousRaccoon.Data.Item;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;

namespace SousRaccoon.Manager
{
    public class GameManager : MonoBehaviour
    {
        #region Singleton
        public static GameManager instance { get { return _instance; } }
        private static GameManager _instance;

        private void Awake()
        {
            // if the singleton hasn't been initialized yet
            if (_instance != null && _instance != this)
            {
                Destroy(this.gameObject);
                return;//Avoid doing anything else
            }
            if (_instance == null)
            {
                _instance = this;
                DontDestroyOnLoad(gameObject);
            }

            if (isDebug)
                Testing();
        }
        #endregion

        public event Action OnChangeLanguageEvent;

        public SceneManagement sceneManagement;

        [Header("Player Data")]
        public PlayerDataBase playerDataBase;
        public PlayerSaveData playerSaveData;

        [Header("Asset Data")]
        public SpriteResourceSO spriteResource;

        public GameObject playerPrefab;

        public int currentSaveSlot;

        [Header("Stage List")]
        public StageListDataSO stageListData;

        public int currentLevelIndex; //Use For Check Level Index

        public List<AllItemDataEachList> allItemDataEachStage;

        public void ClearAllData()
        {
            PlayerPrefs.DeleteAll();
        }

        #region Currency
        public int PlayerMoney { get; private set; }

        public bool isDebug;

        public void Testing()
        {
            PlayerSaveData saveData = new PlayerSaveData
            {
                LevelSpeed = 0,
                LevelRollCooldown = 0,
                LevelCombat = 0,
                LevelHeal = 0,
                LevelCustomer = 0,
                Skin = 0,
                MoneyCurrency = 0,
            };

            playerSaveData = saveData;
        }

        public string GetSceneDebugStage(int levelIndex)
        {
            currentLevelIndex = levelIndex - 1;
            return stageListData.stageLists[1].sceneNameList[levelIndex - 1];
        }

        public string GetSceneLevel(int levelIndex)
        {
            currentLevelIndex = levelIndex;
            return stageListData.stageLists[levelIndex].sceneNameList[0];
        }

        public void SetCurrency()
        {
            PlayerMoney = PlayerPrefs.GetInt($"PLAYER_MONEY_CURRENCY_SAVE_{currentSaveSlot}");

            SaveMoney();
        }

        public void AddMoney(int money)
        {
            PlayerMoney += money;
            SaveMoney();
        }

        public void RemoveMoney(int money)
        {
            PlayerMoney -= money;
            SaveMoney();
        }

        private void SaveMoney()
        {
            playerSaveData.MoneyCurrency = PlayerMoney;

            PlayerPrefs.SetInt($"PLAYER_MONEY_CURRENCY_SAVE_{currentSaveSlot}", PlayerMoney);
        }

        public void SaveUnlockStage(int stageUnlockIndex)
        {
            playerSaveData.StageUnlock = stageUnlockIndex;

            PlayerPrefs.SetInt($"PLAYER_STATE_UNLOCK_SAVE_{currentSaveSlot}", stageUnlockIndex);
        }

        public void SaveRunComplete(int runCompleteIndex)
        {
            playerSaveData.RunComplete += runCompleteIndex;

            PlayerPrefs.SetInt($"RUN_COMPLETE_{currentSaveSlot}", playerSaveData.RunComplete);
        }
        #endregion

        public void GetRandomMap(int stageIndex, out string oldMapName, out int oldMapIndex, out string newMapName, out int newMapIndex)
        {
            // กำหนดค่า oldMapName ก่อน
            string currentStage = SceneManager.GetActiveScene().name;
            oldMapName = currentStage;

            // หา Index ของ Stage ปัจจุบันใน List
            oldMapIndex = stageListData.stageLists[stageIndex].sceneNameList.IndexOf(oldMapName);

            // กรองเฉพาะ Stage ที่ไม่ใช่ Stage ปัจจุบัน
            List<string> availableStages = stageListData.stageLists[stageIndex].sceneNameList
                .Where(stage => stage != currentStage) // ใช้ตัวแปรแทน oldMapName
                .ToList();

            // เช็คว่ามี Stage ให้สุ่มหรือไม่
            if (availableStages.Count == 0)
            {
                Debug.LogWarning("ไม่มี Stage ให้สุ่ม!");
                newMapName = null;
                newMapIndex = -1; // ใช้ -1 เพื่อบอกว่าไม่มีด่านให้สุ่ม
                return;
            }

            // สุ่ม Stage จาก List ที่เหลือ
            newMapName = availableStages[UnityEngine.Random.Range(0, availableStages.Count)];

            // หา Index ของ Stage ที่สุ่มได้
            newMapIndex = stageListData.stageLists[stageIndex].sceneNameList.IndexOf(newMapName);
        }

        public void OnUpdateLanguage()
        {
            OnChangeLanguageEvent?.Invoke();
        }

        public void AddOrUpdateEvent(EventTrigger trigger, EventTriggerType type, System.Action action)
        {
            var entry = trigger.triggers.FirstOrDefault(e => e.eventID == type);
            if (entry == null)
            {
                entry = new EventTrigger.Entry { eventID = type };
                trigger.triggers.Add(entry);
            }

            // ป้องกันการเพิ่ม Callback ซ้ำ (เลือกใช้ถ้าจำเป็น)
            if (!entry.callback.GetPersistentEventCount().Equals(0))
            {
                for (int i = 0; i < entry.callback.GetPersistentEventCount(); i++)
                {
                    var methodName = entry.callback.GetPersistentMethodName(i);
                    if (methodName == action.Method.Name)
                        return; // มีอยู่แล้ว
                }
            }

            entry.callback.AddListener((data) => action.Invoke());
        }

        public void ChangeUISelectNav(GameObject newButtonUI)
        {
            // ล้าง Selection ก่อน เพื่อป้องกันบั๊กบาง UI ไม่ยอมเปลี่ยน
            EventSystem.current.SetSelectedGameObject(null);

            // เลือก UI ตัวแรก
            EventSystem.current.SetSelectedGameObject(newButtonUI

using SousRaccoon.Data;
using SousRaccoon.Kitchen;
using SousRaccoon.Player;
using SousRaccoon.UI.ShopMerchant;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace SousRaccoon.Manager
{
    public class ShopMerchantManager : MonoBehaviour
    {
        [SerializeField] private GameObject merchantPrefab;
        [SerializeField] private Transform merchantSpawnPoint;
        [SerializeField] private float merchantLookAtTime;

        [Header("UI")]
        [SerializeField] private UIShopMerchantPanel merchantPanel;
        [SerializeField] private GameObject contentShop;

        public ShopMerchantItemDataBase coinExchangePerk;

        // เปลี่ยนให้ Action รับ int เพิ่ม
        private Dictionary<StatType, Action<List<StatModifier>>> statUpdateActions;

        public BarricadeManager barricadeManager;

        public HelperGiverAI helperGiverAIPref; // Assign By Prefab

        public Transform helperSpawnPoint;
        public Transform helperTrashPoint;

        public HelperGiverAI currentHelperGiver;

        public bool isShopOpen;
        public bool hasMoveIGD;

        [HideInInspector] public bool hasPerkSetup = false;

        private void Start()
        {
            barricadeManager = FindAnyObjectByType<BarricadeManager>();

            // Initialize the dictionary with stat update methods
            statUpdateActions = new Dictionary<StatType, Action<List<StatModifier>>>()
            {
                { StatType.MoveSpeed, ApplyMoveSpeed },
                { StatType.RollCDR, ApplyRollCoolDown },
                { StatType.RollRange, ApplyRollRange },
                { StatType.ATKSpeed, ApplyAttackSpeed },
                { StatType.ATKDamage, ApplyDamage },
                { StatType.Stun, ApplyStunRate },
                { StatType.HealRate, ApplyHealRate },
                { StatType.HealRange, ApplyHealRange },
                { StatType.TwoHand, ApplyTwoHand },
                { StatType.CustomerMoneyDrop, ApplyCustomerMoneyDrop },
                { StatType.CoinSpwnRate, ApplyCoinSpawnRate },
                { StatType.CookSpeedChef, ApplySpeedChef },
                { StatType.AngryLimitChef, ApplyAngryLimitChef },
                { StatType.Money, ApplyMoney },
                { StatType.BarricadeStat, ApplyBarricadeStat },
                { StatType.HelperGiverStat, ApplyHelperGiverStat },
                { StatType.CoinExchange, ApplyCoinExchange},

            };

            StartCoroutine(WaitAllThingSet());
        }

        private IEnumerator WaitAllThingSet()
        {
            yield return new WaitUntil(() =>
                FindObjectOfType<PlayerCombatSystem>() != null &&
                FindObjectOfType<PlayerLocomotion>() != null &&
                FindObjectOfType<SpawnerManager>() != null &&
                FindObjectOfType<ChefAI>() != null &&
                FindObjectOfType<StageScenarioManager>().scenarioSet || !FindObjectOfType<StageScenarioManager>().hasSceneario);

            LoadStatRunStage

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Localization;

namespace SousRaccoon.Data
{
    public enum TypeOfPerk { Status, Currency, }

    [CreateAssetMenu(fileName = "ShopMerchantItemData", menuName = "GameData/ShopMerchantItemData")]
    public class ShopMerchantItemDataBase : ScriptableObject
    {
        public string perkName;
        public LocalizedString perkDisplayName;
        public LocalizedString description;
        public Sprite icon;
        [Space(35)]
        public TypeOfPerk typeOfPerk;
        [Space(20)]
        public List<int> levelPrices;
        public List<PerkStatModifier> statModifiers;
    }

    [System.Serializable]
    public class PerkStatModifier
    {
        public List<StatModifier> modifiers;  // รายการของค่าที่จะเปลี่ยน
    }

    [System.Serializable]
    public class StatModifier
    {
        public StatType stat;  // ประเภทของ Stat เช่น Health, Damage, Speed, IsInvincible

        public float floatValue;  // ค่าแบบ Float
        public int intValue;      // ค่าแบบ Int
        public bool boolValue;    // ค่าแบบ Bool
    }

    public enum StatType
    {
        MoveSpeed, RollCDR, RollRange, ATKSpeed, ATKDamage, Stun, HealRate, HealRange, TwoHand,
        CustomerMoneyDrop,
        CoinSpwnRate,
        CookSpeedChef, AngryLimitChef,
        Money,
        BarricadeStat,
        HelperGiverStat,
        CoinExchange

using SousRaccoon.Data;
using SousRaccoon.Manager;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace SousRaccoon.UI.ShopMerchant
{
    public class UIShopMerchantPanel : MonoBehaviour
    {
        public Button rerollButton;

        public TMP_Text rerollText;

        public int reRollTimes;

        public TMP_Text playerCoinText;

        public UIShopMerchantItemSlot baseSlot;

        public Transform perkLayout;

        public ShopMerchantManager shopMerchantManager;

        public List<ShopMerchantItemDataBase> perkSpawnList = new List<ShopMerchantItemDataBase>();

        //public List<ShopMerchantItemDataBase> perkCurrentList = new List<ShopMerchantItemDataBase>();

        public List<UIShopMerchantItemSlot> uIShopMerchantItemSlots = new List<UIShopMerchantItemSlot>();

        private void OnDestroy()
        {
            if (rerollButton != null)
                rerollButton.onClick.RemoveListener(RerollPerk);
        }

        public void SetUpShopUI()
        {
            rerollText.text = reRollTimes.ToString();
            rerollButton.onClick.AddListener(RerollPerk);
            playerCoinText.text = RunStageManager.instance.PlayerCoin.ToString();
            RandomPerk();
        }

        public void SetUpLastDayShopUI()
        {
            rerollButton.gameObject.SetActive(false);
            playerCoinText.text = RunStageManager.instance.PlayerCoin.ToString();
            CoinExchangePerk();
        }

        public void RandomPerk()
        {
            perkSpawnList = RunStageManager.instance.RandomPerks();

            foreach (var perk in perkSpawnList)
            {
                var perkCurrent = Instantiate(baseSlot, perkLayout);

                var perkLevel = RunStageManager.instance.GetPerkLevel(perk.perkName);

                var canBuy = shopMerchantManager.CheckPlayerCanBuy(perk.levelPrices[perkLevel]);
                perkCurrent.slotData = perk;
                perkCurrent.SetUpSlot(perk.icon, perkLevel + 1, perk.perkDisplayName, perk.description, perk.levelPrices[perkLevel], canBuy, shopMerchantManager);

                //perkCurrentList.Add(perk);
                uIShopMerchantItemSlots.Add(perkCurrent);
            }
        }

        public void CoinExchangePerk()
        {
            var perkCurrent = Instantiate(baseSlot, perkLayout);
            perkCurrent.slotData = shopMerchantManager.coinExchangePerk;
            var perkPrice = RunStageManager.instance.PlayerCoin;
            perkCurrent.SetUpSlot(shopMerchantManager.coinExchangePerk.icon, 0, shopMerchantManager.coinExchangePerk.perkDisplayName, shopMerchantManager.coinExchangePerk.description, perkPrice, true, shopMerchantManager);

            //perkCurrentList.Add(shopMerchantManager.coinExchangePerk);
            uIShopMerchantItemSlots.Add(perkCurrent);
        }

        public void UpdateSlot()
        {
            foreach (var perkSlot in uIShopMerchantItemSlots)
            {
                if (!perkSlot.isSoldOut)
                {
                    var perkLevel = RunStageManager.instance.GetPerkLevel(perkSlot.slotData.perkName);
                    var canBuy = shopMerchantManager.CheckPlayerCanBuy(perkSlot.slotData.levelPrices[perkLevel]);
                    perkSlot.OnUpdateSlot(canBuy);

                }
            }
            playerCoinText.text = RunStageManager.instance.PlayerCoin.ToString();
        }

        public void RerollPerk()
        {
            if (reRollTimes <= 0) return;

            reRollTimes--;

            rerollText.text = reRollTimes.ToString();

            foreach (var perk in uIShopMerchantItemSlots)
            {
                Destroy(perk.gameObject);
            }

            perkSpawnList.Clear();
            uIShopMerchantItemSlots.Clear();

            RandomPerk

using SousRaccoon.Data;
using SousRaccoon.Manager;
using System;
using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;
using UnityEngine.UI;

namespace SousRaccoon.UI.ShopMerchant
{
    public class UIShopMerchantItemSlot : MonoBehaviour
    {
        public event Action<ShopMerchantItemDataBase> EventOnBuyButtonClicked;

        [SerializeField] private Button buyButton;

        [SerializeField] private Image slotIcon;
        [SerializeField] private TMP_Text levelText;
        [SerializeField] private LocalizeStringEvent nameText;
        [SerializeField] private LocalizeStringEvent discriptionText;
        [SerializeField] private TMP_Text priceText;

        [SerializeField] private GameObject soldOutPanel;
        [SerializeField] private GameObject cantBuyButton;

        public ShopMerchantManager shopMerchantManager;

        public ShopMerchantItemDataBase slotData;

        public bool isSoldOut = false;

        protected void Awake()
        {
            buyButton.onClick.AddListener(OnBuyButtonClicked);
        }

        protected void OnDestroy()
        {
            buyButton.onClick.RemoveAllListeners();
            EventOnBuyButtonClicked -= shopMerchantManager.OnBuyingPerk;
        }

        public void SetUpSlot(Sprite icon,
                              int levelOfPerk,
                              LocalizedString nameOfPerk,
                              LocalizedString discriptionOfPerk,
                              int priceOfPerk,
                              bool canBuy,
                              ShopMerchantManager shopManager)
        {
            shopMerchantManager = shopManager;
            EventOnBuyButtonClicked += shopMerchantManager.OnBuyingPerk;

            slotIcon.sprite = icon;
            levelText.text = levelOfPerk.ToString();

            nameText.StringReference = nameOfPerk;
            discriptionText.StringReference = discriptionOfPerk;
            priceText.text = $"{priceOfPerk}";

            cantBuyButton.SetActive(!canBuy);
            buyButton.interactable = canBuy;
        }

        public void OnUpdateSlot(bool canBuy)
        {
            cantBuyButton.SetActive(!canBuy);
            buyButton.interactable = canBuy;
        }

        private void OnBuyButtonClicked()
        {
            Debug.LogError("Buy");
            AudioManager.instance.PlayStageSFXOneShot("CashMoney");
            soldOutPanel.SetActive(true);
            buyButton.interactable = false;
            isSoldOut = true;

            EventOnBuyButtonClicked?.Invoke(slotData

using SousRaccoon.Kitchen;
using SousRaccoon.Manager;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using static SousRaccoon.Customer.CustomerStatus;

namespace SousRaccoon.Customer
{
    public class CustomerMovement : MonoBehaviour
    {
        public const float THINK_TIME_MIN = 2;
        public const float THINK_TIME_MAX = 4;
        public const float EATING_TIME = 7.5f;

        NavMeshAgent agent;
        StageManager stateManager;
        CustomerStatus status;
        Animator animator;
        Vector3 targetDestination;

        [SerializeField] public ActionState state;
        [SerializeField] float moveSpeed;
        [SerializeField] float hurtBuffSpeed;
        [SerializeField] float rotationSpeed;
        [SerializeField] float lockDistance;

        [SerializeField] float hurtBuffDuration;
        private Coroutine currentHurtBuffCoroutine;

        [SerializeField] Chair currentChair;
        [SerializeField] Table currentTable;
        private static object chairLock = new object();

        [SerializeField] GameObject eatProp;
        [SerializeField] GameObject orderProp;
        [SerializeField] Animator orderAnim;
        [SerializeField] bool fixSittingAnim;
        [SerializeField] float newTimeWaiting;

        [Header("Money")]
        [SerializeField] GameObject moneyDropUI;
        [SerializeField] TMP_Text moneyText;

        [HideInInspector] public bool isOverThinking = false;

        bool isSit = false; //Cheack Chair For Trash

        public enum ActionState
        {
            Idle,
            Walk,
            Sit,
            Menu,
            Wait,
            Eat,
            Getup,
            Die,
            Upset,
        }

        // Start is called before the first frame update
        void Start()
        {
            agent = GetComponent<NavMeshAgent>();
            status = GetComponent<CustomerStatus>();
            animator = GetComponentInChildren<Animator>();
            stateManager = FindAnyObjectByType<StageManager>();

            agent.speed = moveSpeed;

            // ในการจองเก้าอี้ใน Start()
            lock (chairLock)
            {
                currentChair = stateManager.GetAvailableChair(out var table);

                if (currentChair == null || stateManager.currentCustomerDieCount > 0)
                    StartIdle();
                else
                {
                    currentTable = table;
                    currentTable.OccupyChair(currentChair); // จองเก้าอี้
                    StartWalking(currentChair.walkInPositon.position);
                }
            }

            status.EnterUIState(UIState.normal);

        }

        // Update is called once per frame
        void Update()
        {
            if (state == ActionState.Walk)
            {
                RotateTowardsTarget();
            }

            switch (state)
            {
                case ActionState.Idle:
                    HandleIdle();
                    break;
                case ActionState.Walk:
                    HandleWalking();
                    break;
                case ActionState.Sit:
                    HandleSit();
                    break;
                case ActionState.Menu:
                    HandleMenu();
                    break;
                case ActionState.Wait:
                    HandleWait();
                    break;
                case ActionState.Eat:
                    HandleEat();
                    break;
                case ActionState.Getup:
                    HandleGetUp();
                    break;
                case ActionState.Die:
                    break;
                case ActionState.Upset:
                    HandleUpset();
                    break

using SousRaccoon.Data;
using SousRaccoon.Manager;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.VFX;

namespace SousRaccoon.Customer
{
    public class CustomerStatus : MonoBehaviour
    {
        [HideInInspector] public CustomerMovement movement;
        [HideInInspector] public bool canGiveOrder = false;

        [Header("Time")]
        // TODO : maxHealthTime เดี๋ยวจะไปดึงมาจาก Player Upgrade
        // Health Time
        public float maxHealthTime;
        public float currentHealthTime;
        public float countDownPerSecond = 1f; // damage dealt per second
        public float countDownPlusWaiting = 0.25f; // damage dealt per second

        [Header("Perk")]
        public int blockTimes = 0;

        public int maxMoneyDropRunStage;
        public int midMoneyDropRunStage;
        public int minMoneyDropRunStage;

        [SerializeField] int maxMoneyDrop;
        [SerializeField] int midMoneyDrop;
        [SerializeField] int minMoneyDrop;

        [Header("Take Damage")]
        [SerializeField] protected VisualEffect takeDamageVFX;
        [SerializeField] protected SkinnedMeshRenderer baseMeshRenderer;
        [SerializeField] protected Material baseMat;
        [SerializeField] protected Material takeDamageMat;
        [SerializeField] protected float matDuration;
        Coroutine takeDamageCoroutine;

        [Header("Heal")]
        public Animator healAnim;

        [Header("Condition")]
        public bool isCountDownOverTime = false; // flag to check if health is decreasing over time
        public bool isDead = false;
        public bool isUpset = false;
        public bool canHeal = true;
        public bool isTutorial = false;
        public bool isWaiting = false;

        GameObject currentPanel;

        public int htState;

        [SerializeField] Sprite greenBar;
        [SerializeField] Sprite yellowBar;
        [SerializeField] Sprite redBar;
        [SerializeField] Sprite purpleBar;

        [SerializeField] GameObject htBarPanel;
        [SerializeField] Image htBar; // health bar image

        [Header("Order")]
        [SerializeField] GameObject orderPanel; // Panel
        [SerializeField] Image orderOrderIcon; // Order Icon in order State
        [SerializeField] GameObject menuIcon;
        [SerializeField] GameObject waterMenuIcon;

        [Header("Wait")]
        [SerializeField] GameObject waitPanel; // Panel
        [SerializeField] Image waitOrderIcon; // Order Icon in wait State

        [Header("Upset")]
        [SerializeField] GameObject AngryVFX;

        [Header("Dead")]
        public GameObject deadPref;

        [Header("Debug")]
        //TODO : Delete it. This is for Debug
        public TMP_Text htBarText; // health bar text

        [SerializeField] public UIState currentState;

        public enum UIState
        {
            normal,
            thinking,
            order,
            wait,
            dead,
            getup,
            upset,
        }

        // Start is called before the first frame update
        void Start()
        {
            LoadPlayerStatus();

            movement = GetComponent<CustomerMovement>();
            currentPanel = null;
            canHeal = true;
            UpdateHealthBar(); // Initialize health bar on start
        }

        // Update is called once per frame
        void Update()
        {
            if (isDead || isUpset) return;

            if (isCountDownOverTime && !isTutorial)
            {
                HealthTimeCount();
                UpdateHealthBar

CustomerStatus.cs

System

CustomerMovement.cs

Manager System

GameManager.cs

SceneManagement.cs