using UdonSharp; using UnityEngine; using VRC.SDK3.Data; using VRC.SDK3.UdonNetworkCalling; using VRC.SDKBase; using VRC.Udon.Common; 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 { [SerializeField] private CaseManager _CaseManager; [SerializeField] private FloorMap[] _Maps; [SerializeField] private FloorMapMarker[] _Markers; [SerializeField] private AudioManager _AudioManager; [UdonSynced, FieldChangeCallback(nameof(CurrentlyActiveMap))] private ContinentMap _CurrentlyActiveMap = ContinentMap.INDEX_MAX; [UdonSynced] private int _StageIndex = 0; private DataDictionary _ContinentData; [UdonSynced] private GameStatus _GameStatus = GameStatus.Pregame; [UdonSynced] private int _Timer = TIMER_LENGTH; private const float LENGTH_OF_ONE_SECOND = 1.022222222222222222222f; private const int TIMER_LENGTH = 45; [UdonSynced] private int _SuccessCounter = 0; [UdonSynced] private int _FailureCounter = 0; private const int MAX_FAILURE_COUNT = 2; private const int MAX_SUCCESS_COUNT = 8; public override void InitialiseGameMode() { _StageIndex = 0; _SuccessCounter = 0; _FailureCounter = 0; _Timer = TIMER_LENGTH; // We'll need to reset the markers here, too. RequestSerialization(); base.InitialiseGameMode(); } public override void LoadQuestionData(DataToken Data) { _ContinentData = Data.DataDictionary; if (_ContinentData.ContainsKey("Continent")) { CurrentlyActiveMap = (ContinentMap)(int)_ContinentData["Continent"].Number; RequestSerialization(); SendCustomEventDelayedSeconds(nameof(GenerateRandomMapLocations), 1.0f); } else { Debug.LogError("Malformed round data. Ensure Round 3 contains a continent to use for the map."); } EnableInteraction("Display Briefing"); } public void GenerateRandomMapLocations() { FloorMap Map = GetCurrentMap(); Map.RandomiseCountries(); } private void ActivateMap() { for (int i = 0; i < _Maps.Length; i++) { FloorMap Map = _Maps[i]; if (Map != null) { Map.gameObject.SetActive(false); } } FloorMap CurrentMap = _Maps[(int)CurrentlyActiveMap]; if (CurrentMap != null) { CurrentMap.gameObject.SetActive(true); } } private void DisplayBriefing() { HostCardCaptureCarmenExplainerInterface CaptureCarmenExplainerInterface = (HostCardCaptureCarmenExplainerInterface)GetHostCardInterface(RoundSegmentType.CaptureCarmenExplainer); CaptureCarmenExplainerInterface.HeaderUI.text = RoundSegmentTypeToString(RoundSegmentType.CaptureCarmenExplainer); EnableInteraction("Begin"); } public void BeginRound() { NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)GetCurrentMarker(), NetworkEventTarget.Owner, "Activated", true); UpdateInterface(); StartTimer(); } private void StartTimer() { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.CarmenChaseMusic); _GameStatus = GameStatus.Begin; _Timer = TIMER_LENGTH; SendCustomEventDelayedSeconds(nameof(TickTimer), LENGTH_OF_ONE_SECOND); RequestSerialization(); } public void TickTimer() { _Timer--; if (_Timer < 0) { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.Owner, nameof(GameHasBeenLost), false); return; } SendCustomEventDelayedSeconds(nameof(TickTimer), LENGTH_OF_ONE_SECOND); RequestSerialization(); } public void CorrectResponse() { PlayCorrectSound(); NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)GetCurrentMarker(), NetworkEventTarget.Owner, "Activated", false); _FailureCounter = 0; _SuccessCounter++; if (_SuccessCounter >= MAX_SUCCESS_COUNT) { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.Owner, nameof(GameHasBeenWon)); } else { SetUpNextCountry(); } RequestSerialization(); } public void IncorrectResponse() { _FailureCounter++; if (_FailureCounter >= MAX_FAILURE_COUNT) { _FailureCounter = 0; NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)GetCurrentMarker(), NetworkEventTarget.Owner, "Activated", false); SetUpNextCountry(); } PlayIncorrectSound(); } public FloorMap GetCurrentMap() { return _Maps[(int)CurrentlyActiveMap]; } public FloorMapMarker GetCurrentMarker() { return _Markers[GetCurrentMap().GetCurrentCountryIndex()]; } public string GetCurrentCountry() { return GetCurrentMap().GetCurrentCountry(); } public string GetCurrentCity() { return GetCurrentMap().GetCurrentCity(); } public void SetUpNextCountry() { int NextCountry = GetCurrentMap().NextCountry(); if (NextCountry < 0) { // If we ran out of countries, lose the game here. NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.Owner, nameof(GameHasBeenLost), true); return; } NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)GetCurrentMarker(), NetworkEventTarget.Owner, "Activated", true); UpdateInterface(); } [NetworkCallable] public void GameHasBeenWon() { if ((int)_GameStatus <= (int)GameStatus.Begin) { GameStatusUpdate(GameStatus.Win); HostCardBetweenRoundsInterface GameWinInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); GameWinInterface.HeaderUI.text = "The player has won the game. " + _Timer + " seconds to spare."; NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlaySFXLoop", SFXEventType.CarmenInJail); SendCustomEventDelayedSeconds(nameof(StopFinalRoundMusic), 1.0f); SendCustomEventDelayedSeconds(nameof(PlayWindDownMusic), 5.0f); SendCustomEventDelayedSeconds(nameof(EndCarmenInJailSFX), 7.0f); } } public void StopFinalRoundMusic() { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "StopMusic"); } public void PlayWindDownMusic() { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.CarmenSandiegoWindDown); EnableInteraction("Do It, Rockapella!"); } public void EndCarmenInJailSFX() { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "StopSFX"); } [NetworkCallable] public void GameHasBeenLost(bool RanOutOfMarkers) { if ((int)_GameStatus != (int)GameStatus.Win) { for (int i = 0; i < _Markers.Length; i++) { NetworkCalling.SendCustomNetworkEvent( (IUdonEventReceiver)_Markers[i], NetworkEventTarget.Owner, "Activated", false); } GameStatusUpdate(RanOutOfMarkers ? GameStatus.RanOutOfMarkers : GameStatus.RanOutOfTime); HostCardBetweenRoundsInterface GameLossInterface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); GameLossInterface.HeaderUI.text = "The player has lost. " + _SuccessCounter + " countries in " + TIMER_LENGTH + " seconds."; StopFinalRoundMusic(); SendCustomEventDelayedSeconds(nameof(PlayWindDownMusic), 2.5f); } } private void DoItRockapella() { HostCardBetweenRoundsInterface Interface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); Interface.HeaderUI.text = "Rockin' it acapella"; NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlayMusicLoop", MusicEventType.CarmenSandiegoTheme); EnableInteraction("End Game"); } private void EndGame() { HostCardBetweenRoundsInterface Interface = (HostCardBetweenRoundsInterface)GetHostCardInterface(RoundSegmentType.BetweenSegments); Interface.HeaderUI.text = "Game is over. Load a new case file to start again."; NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "StopMusic"); EnableInteraction("Game is over. Load a new case file to start again."); } private void GameStatusUpdate(GameStatus NewStatus) { if ((int)_GameStatus <= (int)GameStatus.Begin) { _GameStatus = NewStatus; } RequestSerialization(); } public void PlayCorrectSound() { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlaySFX", SFXEventType.MapCorrect); } public void PlayIncorrectSound() { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All, "PlaySFX", SFXEventType.MapIncorrect); } private void UpdateInterface() { HostCardCaptureCarmenInterface CaptureCarmenInterface = (HostCardCaptureCarmenInterface)GetHostCardInterface(RoundSegmentType.CaptureCarmen); CaptureCarmenInterface.HeaderUI.text = RoundSegmentTypeToString(RoundSegmentType.CaptureCarmen); CaptureCarmenInterface.CommentUI.text = GetCurrentCity() + ", " + GetCurrentCountry(); } 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: BeginRound(); break; case 3: DoItRockapella(); break; case 4: EndGame(); break; } } public ContinentMap CurrentlyActiveMap { set { _CurrentlyActiveMap = value; ActivateMap(); } get => _CurrentlyActiveMap; } }