using UdonSharp; using UnityEngine; using UnityEngine.Video; using VRC.SDK3.Data; using VRC.SDK3.UdonNetworkCalling; using VRC.SDKBase; using VRC.Udon.Common.Interfaces; public enum ContinentMap { Africa, Asia, Europe, NorthAmerica, Oceania, SouthAmerica, INDEX_MAX } public enum GameStatus { Pregame, Begin, RanOutOfTime, RanOutOfMarkers, Win } [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class GameManagerRound3 : GameManagerBase { [Space] [SerializeField] private FloorMap[] _Maps; [SerializeField] private FloorMapMarker[] _Markers; [SerializeField] private CaptureCarmenNewspaper _CaptureCarmenNewspaper; [SerializeField] private NewspaperDisplay _NewspaperPublicDisplay; [SerializeField] private TimerDisplay _TimerPublicDisplay; [SerializeField] private SimpleEnable _Scoreboard; [SerializeField] private CameraOverlay[] _TimerCameraOverlays; [SerializeField] private CameraOverlay[] _NewspaperCameraOverlays; [SerializeField] private RandomVideoPlayer _EndingPlayer; [UdonSynced, FieldChangeCallback(nameof(CurrentlyActiveMap))] private ContinentMap _CurrentlyActiveMap = ContinentMap.INDEX_MAX; [UdonSynced, FieldChangeCallback(nameof(ActiveMarker))] private int _ActiveMarker = 0; [UdonSynced] private int _StageIndex = 0; private DataDictionary _ContinentData; [UdonSynced] private GameStatus _GameStatus = GameStatus.Pregame; [UdonSynced] private bool _RunTimer = false; [UdonSynced] private int _Timer = TIMER_LENGTH; private const float LENGTH_OF_ONE_SECOND = 1.044444444444444444444f; private const int TIMER_LENGTH = 45; [UdonSynced, FieldChangeCallback(nameof(SuccessCounter))] private int _SuccessCounter = 0; [UdonSynced, FieldChangeCallback(nameof(FailureCounter))] private int _FailureCounter = 0; private const int MAX_SUCCESS_COUNT = 8; private const int MAX_FAILURE_COUNT = 2; private CameraControllerRound3 _CameraControllerRound3 = null; private float _VideoPlayerTimer = -1.0f; void Start() { _CameraControllerRound3 = (CameraControllerRound3)_CameraController; if (_CameraControllerRound3 == null) { Debug.LogError("[GameManagerRound3] Camera controller is the wrong type. This will cause a crash for sure."); } } void Update() { if (IsRoundInitialised()) { if (_VideoPlayerTimer > 0.0f) { _VideoPlayerTimer -= Time.deltaTime; if (_VideoPlayerTimer <= 0.0f) { EndVideoPlayerCameraSwitch(); } } } } public override void InitialiseGameMode() { _GameStatus = GameStatus.Pregame; _StageIndex = 0; SuccessCounter = 0; FailureCounter = 0; _Timer = TIMER_LENGTH; _RunTimer = false; _VideoPlayerTimer = -1.0f; InitialiseMarkers(); _EndingPlayer.PlayVideo = false; _CaptureCarmenNewspaper.ResetAnimation(); _NewspaperPublicDisplay.Activate(false); _TimerPublicDisplay.Initialise(); _Scoreboard.Enable(false); foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Overlay.EnableOverlayElements(false); } foreach (CameraOverlay Overlay in _NewspaperCameraOverlays) { Overlay.EnableOverlayElements(false); } SendCustomNetworkEvent(NetworkEventTarget.All, nameof(EnableAudienceSilencer), false); _CameraControllerRound3.InitialiseCameras(); _CameraControllerRound3.PlayIFeelGood(true); DeinitialiseGameplayCameraFollowers(); DeinitialiseEndingCameraFollowers(); base.InitialiseGameMode(); RequestSerialization(); } public override void DeinitialiseGameMode() { _RunTimer = false; _EndingPlayer.PlayVideo = false; _CameraControllerRound3.DeinitialiseCameras(); _NewspaperPublicDisplay.Activate(false); _TimerPublicDisplay.Activate(false); foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Overlay.EnableOverlayElements(false); } foreach (CameraOverlay Overlay in _NewspaperCameraOverlays) { Overlay.EnableOverlayElements(false); } _VideoPlayerTimer = -1.0f; base.DeinitialiseGameMode(); } public override void SetOwnershipOfObjects(VRCPlayerApi NewOwner) { for (int i = 0; i < _Maps.Length; i++) Networking.SetOwner(NewOwner, _Maps[i].gameObject); for (int i = 0; i < _Markers.Length; i++) Networking.SetOwner(NewOwner, _Markers[i].gameObject); Networking.SetOwner(NewOwner, _CaptureCarmenNewspaper.gameObject); Networking.SetOwner(NewOwner, _NewspaperPublicDisplay.gameObject); Networking.SetOwner(NewOwner, _TimerPublicDisplay.gameObject); Networking.SetOwner(NewOwner, _EndingPlayer.gameObject); foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Networking.SetOwner(NewOwner, Overlay.gameObject); } foreach (CameraOverlay Overlay in _NewspaperCameraOverlays) { Networking.SetOwner(NewOwner, Overlay.gameObject); } Networking.SetOwner(NewOwner, _CameraController.gameObject); Networking.SetOwner(NewOwner, _CameraControllerRound3.gameObject); base.SetOwnershipOfObjects(NewOwner); } private void InitialiseMarkers() { for (int i = 0; i < _Markers.Length; i++) { Networking.SetOwner(Networking.GetOwner(gameObject), _Markers[i].gameObject); _Markers[i].SendCustomNetworkEvent(NetworkEventTarget.All, "Initialise"); } GetCurrentMarker().SendCustomNetworkEvent(NetworkEventTarget.All, "SetPickupable", true); } public override void LoadQuestionData(DataToken Data) { _ContinentData = Data.DataDictionary; if (_ContinentData.ContainsKey("Continent")) { CurrentlyActiveMap = (ContinentMap)(int)_ContinentData["Continent"].Number; RequestSerialization(); } else { Debug.LogError("Malformed round data. Ensure Round 3 contains a continent to use for the map."); } InitialiseMarkers(); GetCurrentMap().RandomiseCountries(); EnableInteraction("Display Briefing"); } private void ActivateMap() { for (int i = 0; i < _Maps.Length; i++) { FloorMap Map = _Maps[i]; if (Map != null) { Map.Activate = false; } } FloorMap CurrentMap = _Maps[(int)CurrentlyActiveMap]; if (CurrentMap != null) { CurrentMap.Activate = true; } } private void DisplayBriefing() { ActiveMarker = 0; HostCardCaptureCarmenExplainerInterface CaptureCarmenExplainerInterface = (HostCardCaptureCarmenExplainerInterface)GetHostCardInterface(RoundSegmentType.CaptureCarmenExplainer); CaptureCarmenExplainerInterface.HeaderUI.text = RoundSegmentTypeToString(RoundSegmentType.CaptureCarmenExplainer); _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "FadeOutMusic"); _CameraControllerRound3.PlayIFeelGood(false); _CameraControllerRound3.ActivateHostPlayerCameraSwitcher(); EnableInteraction("Put " + TIMER_LENGTH + " seconds on the clock"); } private void ActivateTimer() { HostCardBetweenRoundsInterface BetweenRoundsInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); BetweenRoundsInterface.HeaderUI.text = RoundSegmentTypeToString(RoundSegmentType.CaptureCarmen); BetweenRoundsInterface.CommentUI.text = "On your mark...\nGet set..."; _TimerPublicDisplay.Activate(true); _Scoreboard.Enable(true); foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Overlay.EnableOverlayElements(true); } _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFXAtPitch", SFXEventType.Ding, AudioManager.D6); EnableInteraction("...GO!"); } public void BeginRound() { _GameStatus = GameStatus.Begin; UpdateInterface(); _CameraControllerRound3.DisableAllSwitchers(); _CameraControllerRound3.ActivatePlayfieldSwitchTriggerGroup = true; InitialiseGameplayCameraFollowers(); foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Overlay.EnableOverlayElements(true); } GetCurrentMarker().SendCustomNetworkEvent(NetworkEventTarget.Owner, "Activated", true); _EndingPlayer.LoadRandomVideo(); StartTimer(); } private void StartTimer() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.CarmenChaseMusic); _Timer = TIMER_LENGTH; SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(BeginTimerTick)); RequestSerialization(); } [NetworkCallable] public void BeginTimerTick() { _RunTimer = true; SendCustomEventDelayedSeconds(nameof(TickTimer), LENGTH_OF_ONE_SECOND); } public void TickTimer() { if (!_RunTimer) return; _Timer--; _TimerPublicDisplay.SecondsElapsed(TIMER_LENGTH - _Timer); if (_Timer <= 0) { SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(GameIsOver), false, false); return; } BeginTimerTick(); RequestSerialization(); } public void EndTimerEarly() { _Timer = 0; TickTimer(); } [NetworkCallable] public void CorrectResponse() { if (_GameStatus == GameStatus.Begin) { FloorMapMarker CurrentMarker = GetCurrentMarker(); CurrentMarker.SendCustomNetworkEvent(NetworkEventTarget.Owner, "SetLit", true); _TimerPublicDisplay.NewCorrectMarker(); PlayCorrectSound(); SuccessCounter++; if (SuccessCounter >= MAX_SUCCESS_COUNT) { GameIsOver(true, false); } else { SetUpNextCountry(); } RequestSerialization(); } } [NetworkCallable] public void IncorrectResponse() { if (_GameStatus == GameStatus.Begin) { PlayIncorrectSound(); FailureCounter++; if (FailureCounter >= MAX_FAILURE_COUNT) { SetUpNextCountry(); } RequestSerialization(); } } public FloorMap GetCurrentMap() { return _Maps[(int)CurrentlyActiveMap]; } public FloorMapMarker GetCurrentMarker() { return _Markers[ActiveMarker]; } public string GetCurrentCountry() { return GetCurrentMap().GetCountry(ActiveMarker); } public string GetCurrentRegion() { return GetCurrentMap().GetRegion(ActiveMarker); } public string GetCurrentCity() { return GetCurrentMap().GetCity(ActiveMarker); } public void SetUpNextCountry() { GetCurrentMarker().SendCustomNetworkEvent(NetworkEventTarget.All, "Activated", false); FailureCounter = 0; ActiveMarker++; RequestSerialization(); } private void ActivateMarker() { if (_GameStatus == GameStatus.Begin) { if (ActiveMarker >= FloorMap.MAX_SELECTED_COUNTRIES) { // If we ran out of countries, lose the game here. SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(GameIsOver), false, true); return; } UpdateInterface(); GetCurrentMarker().SendCustomNetworkEvent(NetworkEventTarget.Owner, "Activated", true); } _CameraControllerRound3.MarkerCameraAnchorPosition = ActiveMarker; } [NetworkCallable] public void GameIsOver(bool GameWon, bool HaveWeRunOutOfMarkers) { if (GameWon) { _GameHasBeenWon(); } else { _GameHasBeenLost(HaveWeRunOutOfMarkers); } foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Overlay.PlayFadeOutAnimation(); } InitialiseEndingCameraFollowers(); } private void _GameHasBeenWon() { _RunTimer = false; if (_GameStatus == GameStatus.Begin) { GameStatusUpdate(GameStatus.Win); HostCardBetweenRoundsInterface GameWinInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); GameWinInterface.HeaderUI.text = GetRound3PlayerName() + " has won the game."; GameWinInterface.CommentUI.text = "- " + _Timer + " seconds to spare.\n" + "- There's one more thing I want you to do for us. You know what it is..."; _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFXLoop", SFXEventType.CarmenInJail); _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "FadeOutMusic"); SendCustomEventDelayedSeconds(nameof(PlayWindDownMusic), 5.0f); SendCustomEventDelayedSeconds(nameof(EndCarmenInJailSFX), 7.0f); } _CameraControllerRound3.ActivatePlayfieldSwitchTriggerGroup = false; _CameraControllerRound3.DisableAllSwitchers(); _CameraControllerRound3.SwitchToFrontCamera(); } public void PlayWindDownMusic() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.CarmenSandiegoWindDown); EnableInteraction("Do It, Rockapella!"); } public void EndCarmenInJailSFX() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "StopSFX"); _CaptureCarmenNewspaper.PlayWinAnimation(GetRound3PlayerName()); _NewspaperPublicDisplay.Activate(true); foreach (CameraOverlay Overlay in _NewspaperCameraOverlays) { Overlay.EnableOverlayElements(true); } } private void _GameHasBeenLost(bool HaveWeRunOutOfMarkers) { _RunTimer = false; if (_GameStatus == GameStatus.Begin) { GameStatusUpdate(HaveWeRunOutOfMarkers ? GameStatus.RanOutOfMarkers : GameStatus.RanOutOfTime); HostCardBetweenRoundsInterface GameLossInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); GameLossInterface.HeaderUI.text = "The player has run out of " + (HaveWeRunOutOfMarkers ? "markers" : "time") + "."; GameLossInterface.CommentUI.text = "- Found " + SuccessCounter + " countries in " + TIMER_LENGTH + " seconds.\n\n" + "- There's one more thing I want you to do for us. You know what it is..."; _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFX", SFXEventType.TimerEnd); _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "StopMusic"); SendCustomEventDelayedSeconds(nameof(PlayWindDownMusic), 2.5f); SendCustomEventDelayedSeconds(nameof(PlayNewspaperLoseAnimation), 3.0f); } _CameraControllerRound3.ActivatePlayfieldSwitchTriggerGroup = false; _CameraControllerRound3.DisableAllSwitchers(); _CameraControllerRound3.SwitchToFrontCamera(); } public void PlayNewspaperLoseAnimation() { _CaptureCarmenNewspaper.PlayLoseAnimation(); _NewspaperPublicDisplay.Activate(true); foreach (CameraOverlay Overlay in _NewspaperCameraOverlays) { Overlay.EnableOverlayElements(true); } } private void DoItRockapella() { HostCardBetweenRoundsInterface Interface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); Interface.HeaderUI.text = "Rockin' it a capella"; Interface.CommentUI.text = ""; _CaptureCarmenNewspaper.ResetAnimation(); _NewspaperPublicDisplay.Activate(false); _Scoreboard.Enable(false); _TimerPublicDisplay.Activate(false); foreach (CameraOverlay Overlay in _TimerCameraOverlays) { Overlay.EnableOverlayElements(false); } foreach (CameraOverlay Overlay in _NewspaperCameraOverlays) { Overlay.EnableOverlayElements(false); } _CameraControllerRound3.DisableAllSwitchers(); _CameraControllerRound3.PlayDoItRockapella(true); _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "FadeOutMusic"); SendCustomEventDelayedSeconds(nameof(PlayEndingTheme), 1.25f); EnableInteraction("End Game"); } public void PlayEndingTheme() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.CarmenSandiegoTheme); _CameraControllerRound3.ActivateMapToEndingCameraSwitcher(); _EndingPlayer.PlayVideo = true; _VideoPlayerTimer = _EndingPlayer.GetDuration() - _CameraControllerRound3.MapToEndingTimerToggle.GetTimeBetweenCuts(0); } public void EndVideoPlayerCameraSwitch() { _CameraControllerRound3.PlayDoItRockapella(false); _CameraControllerRound3.ActivateFrontOverheadCameraSwitcher(); } private void EndGame() { HostCardBetweenRoundsInterface Interface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); Interface.HeaderUI.text = "Game is over. Load a new case file to start again."; Interface.CommentUI.text = ""; _EndingPlayer.PlayVideo = false; _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "FadeOutMusic"); _CameraControllerRound3.SwitchToFrontCamera(); _CameraControllerRound3.DeinitialiseCameras(); _CameraControllerRound3.PlayIFeelGood(false); _CameraControllerRound3.PlayDoItRockapella(false); _CaseManager.EndGame(); DisableInteraction("Game Over"); } public void PlayCorrectSound() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFX", SFXEventType.MapCorrect); } public void PlayIncorrectSound() { _AudioManager.SendCustomNetworkEvent(NetworkEventTarget.All, "PlaySFX", SFXEventType.MapIncorrect); } private void GameStatusUpdate(GameStatus NewStatus) { if ((int)_GameStatus <= (int)GameStatus.Begin) { _GameStatus = NewStatus; } RequestSerialization(); } private void UpdateInterface() { if (_GameStatus == GameStatus.Begin) { HostCardCaptureCarmenInterface CaptureCarmenInterface = (HostCardCaptureCarmenInterface)GetHostCardInterface(RoundSegmentType.CaptureCarmen); CaptureCarmenInterface.HeaderUI.text = RoundSegmentTypeToString(RoundSegmentType.CaptureCarmen); string City = GetCurrentCity(); string Region = GetCurrentRegion(); string Country = GetCurrentCountry(); if (Region == "" || Region.Contains(City) || Region == Country) { Region = ""; } else { Region += ", "; } CaptureCarmenInterface.CommentUI.text = City + ", " + Region + Country; } } public void RerandomiseMap(bool HardMode = false) { FloorMap CurrentMap = GetCurrentMap(); if (CurrentMap) { GetCurrentMap().RandomiseCountries(HardMode); } } private string GetRound3PlayerName() { string[] CurrentWinner = _CaseManager.GetCurrentWinningPlayers(); if (CurrentWinner == null || CurrentWinner.Length != 1) { return Networking.GetOwner(GetCurrentMarker().gameObject).displayName; } return CurrentWinner[0]; } private void InitialiseGameplayCameraFollowers() { _CameraControllerRound3.FrontCamera_FollowPlayers(new string[1] { GetRound3PlayerName() }); } private void DeinitialiseGameplayCameraFollowers() { _CameraControllerRound3.FrontCamera_StopFollowingPlayers(); } private void InitialiseEndingCameraFollowers() { string[] PlayerFollows = new string[2] { _CaseManager.GetHostOwner().displayName, GetRound3PlayerName() }; _CameraControllerRound3.FrontCamera_FollowPlayers(PlayerFollows); _CameraControllerRound3.OverheadCamera_FollowPlayers(PlayerFollows); } private void DeinitialiseEndingCameraFollowers() { _CameraControllerRound3.FrontCamera_StopFollowingPlayers(); _CameraControllerRound3.OverheadCamera_StopFollowingPlayers(); } protected override HostCardInterfaceBase GetHostCardInterface(RoundSegmentType Question) { return _HostCard.EnableHostCardDisplay(RoundType.CaptureCarmen, Question); } protected override void _HostCardUseButtonDown_Internal() { DisableInteraction(); _StageIndex++; switch (_StageIndex) { case 1: DisplayBriefing(); break; case 2: ActivateTimer(); break; case 3: BeginRound(); break; case 4: DoItRockapella(); break; case 5: EndGame(); break; } } public ContinentMap CurrentlyActiveMap { set { _CurrentlyActiveMap = value; ActivateMap(); } get => _CurrentlyActiveMap; } public int ActiveMarker { set { _ActiveMarker = value; ActivateMarker(); } get => _ActiveMarker; } private int SuccessCounter { set { _SuccessCounter = value; } get => _SuccessCounter; } private int FailureCounter { set { _FailureCounter = value; } get => _FailureCounter; } }