Jamie Greunbaum 674e5b67ef - Created animation for Kneemoi In Jail, thus completing Happy Happy Troy Troy.
- Crane shot in round 3 resets before switching to the ending camera sequence.
- Reworked old credits document to only list purchase requirements.
2026-04-15 04:00:00 -04:00

758 lines
19 KiB
C#

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()
{
base.InitialiseGameMode();
_GameStatus = GameStatus.Pregame;
_StageIndex = 0;
SuccessCounter = 0;
FailureCounter = 0;
_Timer = TIMER_LENGTH;
_RunTimer = false;
_VideoPlayerTimer = -1.0f;
InitialiseMarkers();
GetCurrentMap().RandomiseCountries();
_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();
RequestSerialization();
}
public override void DeinitialiseGameMode()
{
_EndingPlayer.PlayVideo = false;
_CameraControllerRound3.DeinitialiseCameras();
_NewspaperPublicDisplay.Activate(false);
_TimerPublicDisplay.Activate(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");
}
ActiveMarker = 0;
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();
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()
{
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;
}
}