using UdonSharp; using UnityEngine; using VRC.SDK3.Data; using VRC.SDK3.UdonNetworkCalling; using VRC.SDKBase; using VRC.Udon.Common.Interfaces; public enum PanelType { Empty, Loot, Warrant, Crook } [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class GameManagerRound2 : GameManagerBase { [Space] [SerializeField] private Modem _Modem; [SerializeField] private ArrivalDisplay _ArrivalDisplay; [SerializeField] private LocationBoard _LocationBoard; [SerializeField] private JailChain _JailChain; [SerializeField] private JailPhone _JailPhone; [SerializeField] private RandomVideoPlayer _JailPlayer; [UdonSynced, FieldChangeCallback(nameof(Location))] private string _Location = ""; [UdonSynced] private string[] _Landmarks; [UdonSynced] private int _StageIndex = 0; [UdonSynced] private int _CurrentPlayerCounter = 0; [UdonSynced] private string[] _Players = new string[2]; private CameraControllerRound2 _CameraControllerRound2 = null; private readonly Color COLOR_STANDARD = new Color(0.78431f, 0.78431f, 0.78431f); private readonly Color COLOR_RED = new Color(0.78431f, 0.0f, 0.0f); private readonly Color COLOR_YELLOW = new Color(0.78431f, 0.78431f, 0.0f); private readonly Color COLOR_GREEN = new Color(0.0f, 0.78431f, 0.0f); void Start() { _CameraControllerRound2 = (CameraControllerRound2)_CameraController; if (_CameraControllerRound2 == null) { Debug.LogError("Camera controller is the wrong type. This will cause a crash for sure."); } } public override void InitialiseGameMode() { base.InitialiseGameMode(); _StageIndex = 0; InitialiseLocationBoard(); _LocationBoard.SetLootImageURL(_CaseManager.GetLootImage()); _JailChain.Initialise(); _JailPhone.Initialise(); SendCustomNetworkEvent(NetworkEventTarget.All, nameof(EnableAudienceSilencer), true); _CameraControllerRound2.InitialiseCameras(); _CameraControllerRound2.DisableAllSwitchers(); _CameraControllerRound2.ActivateHostAllPlayersCameraTrigger(); RequestSerialization(); } public override void DeinitialiseGameMode() { _JailPhone.Activate = false; _JailChain.Show = false; _CameraControllerRound2.DeinitialiseCameras(); base.DeinitialiseGameMode(); } private void InitialiseLocationBoard() { _LocationBoard.RandomiseLocations(); _LocationBoard.RandomiseMaterials(); LocationBoardReset(); } public override void SetOwnershipOfObjects(VRCPlayerApi NewOwner) { Networking.SetOwner(NewOwner, _Modem.gameObject); Networking.SetOwner(NewOwner, _ArrivalDisplay.gameObject); Networking.SetOwner(NewOwner, _LocationBoard.gameObject); Networking.SetOwner(NewOwner, _JailChain.gameObject); Networking.SetOwner(NewOwner, _JailPlayer.gameObject); Networking.SetOwner(NewOwner, _JailPhone.gameObject); Networking.SetOwner(NewOwner, _CameraController.gameObject); Networking.SetOwner(NewOwner, _CameraControllerRound2.gameObject); base.SetOwnershipOfObjects(NewOwner); } public override void LoadQuestionData(DataToken Data) { DataDictionary LandmarkDictionary = Data.DataDictionary; if (LandmarkDictionary.ContainsKey("Location") && LandmarkDictionary.ContainsKey("Landmarks")) { if (LandmarkDictionary["Landmarks"].TokenType == TokenType.DataList && LandmarkDictionary["Landmarks"].DataList.Count >= 15) { DataList LandmarksList = LandmarkDictionary["Landmarks"].DataList; string[] NewLandmarks = new string[LandmarksList.Count]; for (int i = 0; i < LandmarksList.Count; i++) { if (LandmarksList[i].TokenType == TokenType.DataDictionary) { DataDictionary LandmarkEntry = LandmarksList[i].DataDictionary; if (LandmarkEntry.ContainsKey("Landmark")) { NewLandmarks[i] = LandmarkEntry["Landmark"].String; } else { Debug.LogError("Malformed landmark entry. Ensure the 'Landmark' key exists."); } } else { Debug.LogError("Malformed landmark entry. Ensure each landmark is a dictionary containing a 'Landmark' key."); } } Location = LandmarkDictionary["Location"].String; _Landmarks = NewLandmarks; _LocationBoard.SendCustomNetworkEvent(NetworkEventTarget.All, "PopulateLandmarks", NewLandmarks); LocationBoardReset(); RequestSerialization(); } else { Debug.LogError("Malformed landmark data. Ensure there is a list of at least 15 landmarks."); } } else { Debug.LogError("Malformed round data. Ensure Round 2 contains 'Location' and 'Landmark' keys."); } EnableInteraction("Start Game"); } private void DisplayBriefing() { _CameraControllerRound2.DeactivateHostAllPlayersCameraTrigger(); _CameraControllerRound2.ActivateHostPlayersAndWideShotCameraSwitcher(); HostCardRecoverTheLootExplainerInterface RecoverTheLootInterface = (HostCardRecoverTheLootExplainerInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLootExplainer); RecoverTheLootInterface.HeaderUI.text = RoundSegmentTypeToString(RoundSegmentType.RecoverTheLootExplainer); RecoverTheLootInterface.ExplainerUI.text = RecoverTheLootInterface.ExplainerUI.text .Replace("[[LOOT]]", _CaseManager.GetLoot()) .Replace("[[CROOK]]", _CaseManager.GetCrookName()); _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "FadeOutMusic"); _Modem.gameObject.SetActive(false); EnableInteraction("Begin Round"); } private void BeginRound() { _CurrentPlayerCounter = 0; _Players = _CaseManager.GetCurrentWinningPlayers(); if (_Players == null || _Players.Length != 2) { _Players = new string[2]; _Players[0] = Networking.GetOwner(gameObject).displayName; _Players[1] = _Players[0]; } HostCardRecoverTheLootInterface RecoverTheLootInterface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); RecoverTheLootInterface.SetComment(_Players[_CurrentPlayerCounter % _Players.Length] + ", you're up first.", COLOR_STANDARD); RecoverTheLootInterface.SetLootButton(_LocationBoard.LootLocation); RecoverTheLootInterface.SetWarrantButton(_LocationBoard.WarrantLocation); RecoverTheLootInterface.SetCrookButton(_LocationBoard.CrookLocation); RecoverTheLootInterface.EnableAllPanelButtons(true); for (int i = 0; i < _Landmarks.Length; i++) { RecoverTheLootInterface.AddLandmarkName(i, _Landmarks[i]); } _JailPlayer.VideoIndex = (int)_CaseManager.GetCrook(); NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.RecoverTheLoot); } public void OnTheRightTrack() { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment("On the right track. You get a free turn.", COLOR_GREEN); } public void AlmostThere() { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment("Almost got it. Another free turn.", COLOR_YELLOW); } public void OutOfOrder(PanelType Type) { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); string PanelToken = ""; switch (Type) { case PanelType.Loot: PanelToken = _CaseManager.GetLoot(); break; case PanelType.Warrant: PanelToken = "the warrant"; break; case PanelType.Crook: PanelToken = _CaseManager.GetAccusedCrook(); break; } Interface.SetComment("Found " + PanelToken + ". Remember the order: loot, warrant, crook. Use some strategy.", COLOR_YELLOW); } // All of these next functions are the end of a turn, and should disable // all inputs to prevent messing up the game state. public void NothingThere() { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment("Nothing there.", COLOR_STANDARD); Interface.EnableAllPanelButtons(false); } public void AlreadyTried() { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment("Already tried that one.", COLOR_STANDARD); Interface.EnableAllPanelButtons(false); } public void NiceStrategy() { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment("Nice strategy.", COLOR_GREEN); Interface.EnableAllPanelButtons(false); } // This is for when a player wins the game. This should disable all inputs, // and should also enable victory animations. public void YoureWinner() { string[] Winner = new string[1]; Winner[0] = _Players[_CurrentPlayerCounter % _Players.Length]; _CaseManager.SetCurrentWinningPlayers(Winner); HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment("Winner! Congratulations, " + Winner[0], COLOR_RED); Interface.EnableAllPanelButtons(false); NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "StopMusic"); AdvanceRound(); } private void RoundWinner() { HostCardBetweenRoundsInterface BetweenRoundsInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); BetweenRoundsInterface.HeaderUI.text = "Winner: " + _CaseManager.GetCurrentWinningPlayers()[0]; BetweenRoundsInterface.CommentUI.text = "- You recovered " + _CaseManager.GetLoot() + "\n" + "- You captured " + _CaseManager.GetCrookName() + "\n" + "- Now all you have to do is pull on that chain and put " + _CaseManager.GetCrookName() + " in jail\n\n" + "- We should be receiving a phone call from " + _CaseManager.GetCrookName() + " shortly..."; _JailChain.Show = true; EnableInteraction("Phone Call"); } private void PhoneCall() { HostCardBetweenRoundsInterface BetweenRoundsInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); BetweenRoundsInterface.HeaderUI.text = "Phone Call: " + _CaseManager.GetCrookName(); BetweenRoundsInterface.CommentUI.text = "- You and I are going to " + _CaseManager.ContinentToString(_CaseManager.GetFinalRoundContinent()); _JailPhone.Activate = true; EnableInteraction("Go To The Map"); } private void EndRound() { HostCardBetweenRoundsInterface Interface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); Interface.HeaderUI.text = "Round is over."; Interface.CommentUI.text = "Let's go to the map!"; _CaseManager.ContinueToRound3(); _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.IFeelGood); } public void LocationBoardReset(bool UpdateHostCardInterface = false) { _CurrentPlayerCounter++; NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)_LocationBoard, NetworkEventTarget.All, "ResetPanelBoard"); if (UpdateHostCardInterface) { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.SetComment(_Players[_CurrentPlayerCounter % _Players.Length] + ", your turn.", COLOR_STANDARD); SendCustomEventDelayedSeconds(nameof(EnableAllPanelButtons), 0.5f); } RequestSerialization(); } public void EnableAllPanelButtons() { HostCardRecoverTheLootInterface Interface = (HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot); Interface.EnableAllPanelButtons(true); } public Texture GetCrookPortrait() { return _CaseManager.GetAccusedCrookPortrait(); } public void PlayTheLoot() { _AudioManager.PlaySFX(SFXEventType.TheLoot); } public void PlayTheWarrant() { _AudioManager.PlaySFX(SFXEventType.TheWarrant); } public void PlayTheCrookTheme() { _AudioManager.PlayCrookTheme(_CaseManager.GetCrook()); } protected override HostCardInterfaceBase GetHostCardInterface(RoundSegmentType Question) { return _HostCard.EnableHostCardDisplay(RoundType.RecoverTheLoot, Question); } protected override void _HostCardUseButtonDown_Internal() { DisableInteraction(); AdvanceRound(); } private void AdvanceRound() { _StageIndex++; switch (_StageIndex) { case 1: DisplayBriefing(); break; case 2: BeginRound(); break; case 3: RoundWinner(); break; case 4: PhoneCall(); break; case 5: EndRound(); break; } } public void Button_RevealPanel(int Panel) { ((HostCardRecoverTheLootInterface)GetHostCardInterface(RoundSegmentType.RecoverTheLoot)) .DisablePanelButton(Panel); NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)_LocationBoard, NetworkEventTarget.All, "RevealPanel", Panel); } [NetworkCallable] public void PlayInJailAnimation() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFX", SFXEventType.FogHorn); SendCustomEventDelayedSeconds(nameof(PlayCrookInJail), 1.5f); } public void PlayCrookInJail() { _JailPlayer.PlayVideo = true; _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayCrookInJail", _CaseManager.GetCrook()); SendCustomEventDelayedSeconds(nameof(HideJailChain), 1.5f); } public void HideJailChain() { _JailChain.Show = false; } public void PhoneRing() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFX", SFXEventType.PhoneRing); } public void PlayJailCall() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayJailCall", _CaseManager.GetCrook(), _CaseManager.GetFinalRoundContinent()); } public void Button_RevealPanel1() { Button_RevealPanel(1); } public void Button_RevealPanel2() { Button_RevealPanel(2); } public void Button_RevealPanel3() { Button_RevealPanel(3); } public void Button_RevealPanel4() { Button_RevealPanel(4); } public void Button_RevealPanel5() { Button_RevealPanel(5); } public void Button_RevealPanel6() { Button_RevealPanel(6); } public void Button_RevealPanel7() { Button_RevealPanel(7); } public void Button_RevealPanel8() { Button_RevealPanel(8); } public void Button_RevealPanel9() { Button_RevealPanel(9); } public void Button_RevealPanel10() { Button_RevealPanel(10); } public void Button_RevealPanel11() { Button_RevealPanel(11); } public void Button_RevealPanel12() { Button_RevealPanel(12); } public void Button_RevealPanel13() { Button_RevealPanel(13); } public void Button_RevealPanel14() { Button_RevealPanel(14); } public void Button_RevealPanel15() { Button_RevealPanel(15); } private string PanelTypeToString(PanelType Type) { switch(Type) { case PanelType.Empty: return "Empty"; case PanelType.Loot: return "Loot"; case PanelType.Warrant: return "Warrant"; case PanelType.Crook: return "Crook"; default: return "[[ERROR]]"; } } public string Location { set { _Location = value; _ArrivalDisplay.SetDisplayText(_Location); } get => _Location; } }