using System.Collections; using UnityEngine; using TMPro; using UnityEngine.SceneManagement; using UnityEngine.UI; public class MainMenuManager : MonoBehaviour { public const string MainMenuSceneName = "MainMenu"; const string CryptoAddressPrefsKey = "MainMenu.CryptoAddress"; /// 500 CC fee to process a withdrawal. const int WithdrawalFeeCc = 500; /// $20 USD = 20.0 RC, stored in DB as 80 rc coins (4 coins per 1.0 RC). const int MinimumWithdrawalRcCoins = 80; [Header("Stats")] [SerializeField] private GameObject statsPanel; [SerializeField] private TMP_Text usernameText; [SerializeField] private TMP_Text ccText; [SerializeField] private TMP_Text rcText; [Header("Screens")] public GameObject mainMenuScreen; public GameObject gameModesScreen; public GameObject dummyBuyScreen; public GameObject withdrawalScreen; [Header("Play")] public Button btnPlay; public TMP_Text rcPlayText; public TMP_Text entryFeeTxt; public TMP_Text rcPrizeTxt; [Header("Dummy Buy")] public Button btnBuyUsd5; public Button btnBuyUsd20; public Button btnBuyUsd50; [Header("Withdrawal")] public Button btnWithdrawal; public Button btnPaste; public TMP_InputField inputCryptoAddress; public TMP_Text txtWithdrawStatus; private bool isCoinBuyInProgress; [Header("Audio")] public ToggleButton toggleSfx; public ToggleButton toggleMusic; /// Default play cost (coin units) if /settings is not loaded yet. const int FallbackEntryFeeCoins = 21; int _matchEntryFeeCoins = FallbackEntryFeeCoins; public static MainMenuManager instance; void Awake() { if(LoginManager.instance==null){ SceneManager.LoadScene(0); } instance = this; } void Start() { LoginManager.OnUserDataUpdated += OnUserUpdated; usernameText.text = ""; ccText.text = ""; rcText.text = ""; LoginManager.instance.GetUserData((success, error, user) => { if (success) { OnUserUpdated(user); } else { if (btnPlay != null) btnPlay.interactable = false; if (rcPlayText != null) rcPlayText.text = string.IsNullOrEmpty(error) ? "Could not load profile. Try again." : error; } }); btnBuyUsd5.onClick.AddListener(() => OnBuy(RcPack.Usd5)); btnBuyUsd20.onClick.AddListener(() => OnBuy(RcPack.Usd20)); btnBuyUsd50.onClick.AddListener(() => OnBuy(RcPack.Usd50)); if (inputCryptoAddress != null) { inputCryptoAddress.text = PlayerPrefs.GetString(CryptoAddressPrefsKey, string.Empty); inputCryptoAddress.onValueChanged.AddListener(OnCryptoAddressChanged); } UpdateWithdrawalStatus(); if (btnPaste != null) btnPaste.onClick.AddListener(OnPasteFromClipboard); btnPlay.onClick.AddListener(OnPlay); toggleSfx.onToggleValueChanged.AddListener(OnToggleSfx); toggleMusic.onToggleValueChanged.AddListener(OnToggleMusic); toggleSfx.SetIsOn(AudioManager.instance.IsSFXOn()); toggleMusic.SetIsOn(AudioManager.instance.IsMusicOn()); if (!LevelLoadManager.BlocksMainMenuSettingsBootstrap) StartCoroutine(CoBootstrapSettingsWithoutLoader()); } void OnDestroy(){ LoginManager.OnUserDataUpdated -= OnUserUpdated; toggleSfx.onToggleValueChanged.RemoveListener(OnToggleSfx); toggleMusic.onToggleValueChanged.RemoveListener(OnToggleMusic); } void OnToggleSfx(bool isOn) { AudioManager.instance.SetSfxVolume(isOn ? 1f : 0f); } void OnToggleMusic(bool isOn) { AudioManager.instance.SetMusicVolume(isOn ? 1f : 0f); } void OnPlay() { if (LoginManager.CurrentUser == null) { Debug.LogError("Play blocked: user profile not loaded."); return; } if (LoginManager.CurrentUser.rc < _matchEntryFeeCoins) { Debug.LogError("Not enough RC to play"); return; } if (CupidLobby.instance == null) { Debug.LogError("Play blocked: CupidLobby is missing from this scene."); return; } CupidLobby.instance.Matchmake(); } void OnCryptoAddressChanged(string value) { PlayerPrefs.SetString(CryptoAddressPrefsKey, value ?? string.Empty); PlayerPrefs.Save(); UpdateWithdrawalStatus(); } void UpdateWithdrawalStatus(UserData user = null) { if (txtWithdrawStatus == null) return; UserData u = user ?? LoginManager.CurrentUser; if (u == null) return; if (inputCryptoAddress != null && string.IsNullOrWhiteSpace(inputCryptoAddress.text)) { txtWithdrawStatus.text = "Enter a valid wallet address to withdraw safely."; return; } if (u.rc < MinimumWithdrawalRcCoins) { txtWithdrawStatus.text = "Your RC balance is below the minimum withdrawal amount ($20 USD / 20.0 RC)."; return; } if (u.cc < WithdrawalFeeCc) { txtWithdrawStatus.text = "Withdrawal costs 500 CC. Your CC balance is below 500 CC."; return; } txtWithdrawStatus.text = string.Empty; } void OnPasteFromClipboard() { if (inputCryptoAddress == null) return; string clip = GUIUtility.systemCopyBuffer; if (!string.IsNullOrEmpty(clip)) inputCryptoAddress.text = clip; } void OnBuy(string packId){ if (isCoinBuyInProgress) return; isCoinBuyInProgress = true; SetCoinBuyButtonsInteractable(false); LoginManager.instance.PurchaseRcPack(packId, (success, error) => { if(success){ OnUserUpdated(LoginManager.CurrentUser); AudioManager.instance.PlayCoinsSfx(); } isCoinBuyInProgress = false; SetCoinBuyButtonsInteractable(true); }); } void SetCoinBuyButtonsInteractable(bool interactable) { if (btnBuyUsd5 != null) btnBuyUsd5.interactable = interactable; if (btnBuyUsd20 != null) btnBuyUsd20.interactable = interactable; if (btnBuyUsd50 != null) btnBuyUsd50.interactable = interactable; } // Update is called once per frame void Update() { } void OnUserUpdated(UserData user){ usernameText.text = user.username; ccText.text = user.cc.ToString("N0") + " CC"; rcText.text = CoinHelper.FormatString(user.rc) + " RC"; if (LoginManager.CurrentUser.rc < _matchEntryFeeCoins) { rcPlayText.text = "Not enough RC to play"; btnPlay.interactable = false; } else { rcPlayText.text = ""; btnPlay.interactable = true; } UpdateWithdrawalStatus(user); } /// Called by so the loading overlay stays until matchmaker settings are refreshed. public IEnumerator FinishLoadingScreenAndApplySettings() { yield return CoReadyMatchmakerSettingsThenApply(); } IEnumerator CoBootstrapSettingsWithoutLoader() { yield return null; yield return CoReadyMatchmakerSettingsThenApply(); } IEnumerator CoReadyMatchmakerSettingsThenApply() { const float endpointWaitSec = 30f; float deadline = Time.realtimeSinceStartup + endpointWaitSec; while (!Cupid.IsEndpointReady && Time.realtimeSinceStartup < deadline) yield return null; yield return Cupid.CoRefreshSettings(); ApplyMatchmakerFeeUi(); if (LoginManager.CurrentUser != null) OnUserUpdated(LoginManager.CurrentUser); } void ApplyMatchmakerFeeUi() { if (Cupid.Settings == null) { _matchEntryFeeCoins = FallbackEntryFeeCoins; if (entryFeeTxt != null) entryFeeTxt.text = "—"; if (rcPrizeTxt != null) rcPrizeTxt.text = "—"; return; } CupidSettings s = Cupid.Settings; _matchEntryFeeCoins = s.entry_fee > 0 ? s.entry_fee : FallbackEntryFeeCoins; if (entryFeeTxt != null) { entryFeeTxt.text = s.entry_fee > 0 ? CoinHelper.FormatString(s.entry_fee) + " RC" : "—"; } if (rcPrizeTxt != null) { rcPrizeTxt.text = s.rc_prize > 0 ? CoinHelper.FormatString(s.rc_prize) + " RC" : "—"; } } public void ShowMainMenuScreen(){ statsPanel.SetActive(true); mainMenuScreen.SetActive(true); gameModesScreen.SetActive(false); dummyBuyScreen.SetActive(false); withdrawalScreen.SetActive(false); } public void ShowGameModesScreen(){ statsPanel.SetActive(true); mainMenuScreen.SetActive(false); gameModesScreen.SetActive(true); dummyBuyScreen.SetActive(false); withdrawalScreen.SetActive(false); } public void ShowDummyBuyScreen(){ statsPanel.SetActive(false); mainMenuScreen.SetActive(false); gameModesScreen.SetActive(false); dummyBuyScreen.SetActive(true); withdrawalScreen.SetActive(false); } public void ShowWithdrawalScreen(){ statsPanel.SetActive(false); mainMenuScreen.SetActive(false); gameModesScreen.SetActive(false); dummyBuyScreen.SetActive(false); withdrawalScreen.SetActive(true); UpdateWithdrawalStatus(); } }