using UdonSharp; using UnityEngine; using TMPro; using VRC.SDKBase; using VRC.SDK3.UdonNetworkCalling; using VRC.Udon.Common.Interfaces; using UnityEngine.UI; [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class PlayerPodium : UdonSharpBehaviour { public int PlayerNumber = 0; [SerializeField] private GameManagerRound1 _GameManager; [SerializeField] private GameObject _TeleportButton; [UdonSynced, FieldChangeCallback(nameof(PlayerName))] private string _PlayerName = "Player"; [UdonSynced] private int _PlayerID = -1; [UdonSynced, FieldChangeCallback(nameof(PlayerScore))] private int _PlayerScore = 50; [UdonSynced, FieldChangeCallback(nameof(ShowScoreCard))] private bool _ShowScoreCard = false; [UdonSynced, FieldChangeCallback(nameof(FlashScoreboard))] private bool _FlashScoreboard = false; [UdonSynced, FieldChangeCallback(nameof(PedestalHeight))] private float _PedestalHeight = 0.0f; [UdonSynced, FieldChangeCallback(nameof(EnableOwnershipTransfer))] private bool _EnableOwnershipTransfer = true; [Space] [Header("Objects")] [SerializeField] private ChoiceCardGroup _ChoiceCards; [SerializeField] private RiskCardGroup _RiskCards; [SerializeField] private Buzzer _Buzzer; [SerializeField] private GameObject _Pedestal; [SerializeField] private VideoLoadIndicator _VideoLoadIndicator; [SerializeField] private Transform _AuxiliaryVideoScreen; [SerializeField] private Transform _AuxiliaryMapScreen; [SerializeField] private CustomEventInteraction _OwnershipInteract; [Space] [Header("Effects")] [SerializeField] private GameObject _HighlightEffect; [SerializeField] private GameObject _ScorecardObject; [SerializeField] private TextMeshProUGUI _NameplateUI; [SerializeField] private TextMeshProUGUI _ScorecardUI; [SerializeField] private Image _ScorecardBackground; [Space] [Header("Miscellaneous")] [SerializeField] private Transform _SpawnPoint; private int _FlashingScoreboardCounter = 0; private const int MAX_FLASH_COUNTER = 8; private const float MIN_AVATAR_EYE_HEIGHT = 0.745f; private const float FLASHING_SCOREBOARD_PERIOD = 0.15f; void Start() { ResetPodium(); _Buzzer.SetGameManager(_GameManager); } public override void OnPlayerLeft(VRCPlayerApi Player) { if (Player.playerId == _PlayerID) { ResetOwner(); } base.OnPlayerLeft(Player); } public override void OnAvatarEyeHeightChanged(VRCPlayerApi Player, float PrevEyeHeightAsMeters) { if (Player.playerId == _PlayerID) { AdjustPedestalHeight(Player); if (Player == Networking.LocalPlayer) { Player.TeleportTo(_SpawnPoint.position, _SpawnPoint.rotation); } } base.OnAvatarEyeHeightChanged(Player, PrevEyeHeightAsMeters); } public void SetPlayerName() { if (_PlayerID != -1) { return; } Networking.SetOwner(Networking.LocalPlayer, gameObject); Networking.SetOwner(Networking.LocalPlayer, _ChoiceCards.gameObject); Networking.SetOwner(Networking.LocalPlayer, _RiskCards.gameObject); Networking.SetOwner(Networking.LocalPlayer, _Buzzer.gameObject); Networking.SetOwner(Networking.LocalPlayer, _VideoLoadIndicator.gameObject); PlayerName = Networking.LocalPlayer.displayName; _PlayerID = Networking.LocalPlayer.playerId; AdjustPedestalHeight(Networking.LocalPlayer); EnableOwnershipTransfer = false; RequestSerialization(); } [NetworkCallable] public void ResetOwner() { PlayerName = "Player " + PlayerNumber; _PlayerID = -1; EnableOwnershipTransfer = true; RequestSerialization(); } public int GetPlayerID() { return _PlayerID; } private void AdjustPedestalHeight(VRCPlayerApi Player) { PedestalHeight = Player.GetAvatarEyeHeightAsMeters(); RequestSerialization(); } [NetworkCallable] public void DisplayScore() { ShowScoreCard = true; RequestSerialization(); } private void _DisplayScorecardObject(bool Show) { _ScorecardObject.SetActive(Show); } [NetworkCallable] public void ResetPodium() { ResetOwner(); EnableChoiceCards(false, 0); EnableBuzzer(false); HighlightPodium(false); ShowAuxiliaryVideoScreen(false); ShowAuxiliaryMapScreen(false); PlayerScore = 50; ShowScoreCard = false; } public void DecreaseScoreBy5() { PlayerScore -= 5; RequestSerialization(); } public void IncreaseScoreBy5() { PlayerScore += 5; RequestSerialization(); } [NetworkCallable] public void AdjustScore(int Adjustment) { PlayerScore += Adjustment; RequestSerialization(); } [NetworkCallable] public void EnableChoiceCards(bool Enable, int ColourChoice) { _ChoiceCards.gameObject.SetActive(Enable); _ChoiceCards.ResetCards(ColourChoice); _ChoiceCards.SendCustomNetworkEvent(NetworkEventTarget.Owner, "MakeChoiceTextVisible"); } [NetworkCallable] public void SetCardChoices(string[] Choices, int[] Indices) { _ChoiceCards.SetChoices(Choices, Indices); } [NetworkCallable] public void LockInChoice() { _ChoiceCards.LockInChoice(); _ChoiceCards.SendCustomNetworkEvent(NetworkEventTarget.All, "MakeChoiceTextVisible"); } public bool VerifyMultipleChoiceResponse(int CorrectResponse) { bool IsCorrectResponse = _ChoiceCards.GetSelectedChoice() == CorrectResponse; if (IsCorrectResponse) { SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(AdjustScore), 10); } return IsCorrectResponse; } public int GetColourOptionsCount() { return _ChoiceCards.GetColourOptionsCount(); } [NetworkCallable] public void EnableRiskCards(bool Enable) { _RiskCards.gameObject.SetActive(Enable); _RiskCards.ResetCards(); _RiskCards.SendCustomNetworkEvent(NetworkEventTarget.Owner, "MakeRiskTextVisible"); } [NetworkCallable] public void LockInRisk() { _RiskCards.LockInChoice(); _RiskCards.SendCustomNetworkEvent(NetworkEventTarget.All, "MakeRiskTextVisible"); } [NetworkCallable] public void VerifyFinalRoundResponse(int CorrectResponse) { if (_ChoiceCards.GetSelectedChoice() == CorrectResponse) { SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(AdjustScore), _RiskCards.GetSelectedChoice()); } else { SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(AdjustScore), -_RiskCards.GetSelectedChoice()); } } [NetworkCallable] public void EnableBuzzer(bool Enable) { _Buzzer.gameObject.SetActive(Enable); _Buzzer.transform.localPosition = Vector3.zero; _Buzzer.transform.localEulerAngles = Vector3.zero; } [NetworkCallable] public void StartBuzzedInEffect() { FlashScoreboard = true; RequestSerialization(); } public void TickFlashingScoreboard() { if (_FlashingScoreboardCounter < MAX_FLASH_COUNTER) { _FlashingScoreboardCounter++; switch (_FlashingScoreboardCounter % 2) { case 1: InvertScoreboardColours(); break; case 0: default: ResetScoreboardColours(); break; } SendCustomEventDelayedSeconds(nameof(TickFlashingScoreboard), FLASHING_SCOREBOARD_PERIOD); } else { ResetScoreboardColours(); _FlashingScoreboardCounter = 0; FlashScoreboard = false; } } private void InvertScoreboardColours() { _ScorecardUI.color = Color.black; _ScorecardBackground.color = Color.white; } private void ResetScoreboardColours() { _ScorecardUI.color = Color.white; _ScorecardBackground.color = Color.black; } public void HighlightPodium(bool Highlight) { _HighlightEffect.SetActive(Highlight); } [NetworkCallable] public void ShowAuxiliaryVideoScreen(bool Show) { Vector3 LocalPosition = _AuxiliaryVideoScreen.localPosition; _AuxiliaryVideoScreen.localPosition = new Vector3(LocalPosition.x, Show ? 0.0f : -1000.0f, LocalPosition.z); } [NetworkCallable] public void ShowAuxiliaryMapScreen(bool Show) { Vector3 LocalPosition = _AuxiliaryMapScreen.localPosition; _AuxiliaryMapScreen.localPosition = new Vector3(LocalPosition.x, Show ? 0.0f : -1000.0f, LocalPosition.z); } public void TeleportLocalPlayerToPedestal() { Networking.LocalPlayer.TeleportTo(_SpawnPoint.position, _SpawnPoint.rotation); } public string PlayerName { set { _PlayerName = value; _NameplateUI.text = value; } get => _PlayerName; } public int PlayerScore { set { _PlayerScore = value; _ScorecardUI.text = PlayerScore.ToString(); } get => _PlayerScore; } public bool ShowScoreCard { set { _ShowScoreCard = value; _DisplayScorecardObject(value); } get => _ShowScoreCard; } public bool FlashScoreboard { set { _FlashScoreboard = value; if (_FlashScoreboard) { TickFlashingScoreboard(); } else { _FlashingScoreboardCounter = 0; } } get => _FlashScoreboard; } private float PedestalHeight { set { _PedestalHeight = value; _Pedestal.transform.localPosition = new Vector3( _Pedestal.transform.localPosition.x, -Mathf.Clamp( _PedestalHeight, MIN_AVATAR_EYE_HEIGHT, Networking.LocalPlayer.GetAvatarEyeHeightMaximumAsMeters()), _Pedestal.transform.localPosition.z ); } get => _PedestalHeight; } private bool EnableOwnershipTransfer { set { _EnableOwnershipTransfer = value; _OwnershipInteract.gameObject.SetActive(_EnableOwnershipTransfer); _TeleportButton.SetActive(_EnableOwnershipTransfer); } get => _EnableOwnershipTransfer; } }