Jamie Greunbaum 43bed62c7e - Added a briefing to the beginning of round 2, with intention to add more.
- Cleaned up a lot of code to help make development smoother in the future.
2025-06-17 04:50:05 -04:00

973 lines
30 KiB
C#

using UdonSharp;
using UnityEngine;
using VRC.SDK3.Data;
using VRC.SDK3.UdonNetworkCalling;
using VRC.Udon.Common.Interfaces;
using VRC.SDKBase;
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class GameManagerRound1 : GameManagerBase
{
[SerializeField] private CaseManager _CaseManager;
[UdonSynced] protected bool _GameHasBegun = false;
[UdonSynced] private int _QuestionIndex = 0;
[UdonSynced] private int _QuestionStage = 0;
[UdonSynced] private int _QuestionCorrectResponse = 0;
private DataList _QuestionsList = new DataList();
private DataDictionary _CurrentQuestion;
[UdonSynced] private bool _BuzzInAllowed = false;
[UdonSynced] private bool[] _PlayerBuzzInAllowed;
[UdonSynced] private int _BuzzedInPlayer = 0;
private int[] _FinalRoundPlayersSortedByScore;
[SerializeField] private PlayerPodium[] _PlayerPodiums;
[SerializeField] private AudioManager _AudioManager;
public override void InitialiseGameMode()
{
_GameHasBegun = false;
_QuestionIndex = 0;
_QuestionStage = 0;
_PlayerBuzzInAllowed = new bool[_PlayerPodiums.Length];
ResetBuzzers();
base.InitialiseGameMode();
}
public override void LoadQuestionData(DataToken Data)
{
_QuestionsList.Clear();
HostCardBetweenRoundsInterface Interface =
(HostCardBetweenRoundsInterface)GetHostCardInterface(QuestionType.BetweenRounds);
DataList DataDict = Data.DataList;
for (int i = 0; i < DataDict.Count; i++)
{
if (DataDict[i].TokenType == TokenType.DataDictionary)
{
_QuestionsList.Add(DataDict[i]);
}
}
if (_QuestionsList.Count == 0)
{
Interface.HeaderUI.text =
"Unable to find any questions. Ensure the root array elements are all objects.";
return;
}
Interface.HeaderUI.text =
"Found " + _QuestionsList.Count + " questions in this case file. Press 'Use' button to show scores.";
// Reset podiums on a successful case load
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[i],
NetworkEventTarget.All,
"ResetPodium");
}
_GameHasBegun = false;
EnableInteraction("Start Game");
}
private void NewMultipleChoiceQuestion()
{
HostCardMultipleChoiceInterface Interface =
(HostCardMultipleChoiceInterface)GetHostCardInterface(QuestionType.MultipleChoice);
ResetMultipleChoiceInterface(Interface);
Interface.HeaderUI.text = QuestionTypeToString((QuestionType)((int)_CurrentQuestion["Type"].Number));
DataList ClueStrings = _CurrentQuestion["Clues"].DataList;
for (int i = 0; i < Interface.CluesUI.Length && i < ClueStrings.Count; i++)
{
Interface.CluesUI[i].text = ClueStrings[i].ToString();
}
DataList Choices = _CurrentQuestion["Choices"].DataList;
for (int i = 0; i < Choices.Count && i < Interface.ChoiceUI.Length; i++)
{
Interface.ChoiceUI[i].text = Choices[i].ToString();
}
_QuestionCorrectResponse = (int)_CurrentQuestion["Correct Response"].Number;
EnableInteraction("Reveal Choice 1");
}
private void MultipleChoiceRevealChoices()
{
SendCustomEvent(nameof(MultipleChoiceRevealChoice1));
SendCustomEventDelayedSeconds(nameof(MultipleChoiceRevealChoice2), 1.25f);
SendCustomEventDelayedSeconds(nameof(MultipleChoiceRevealChoice3), 2.5f);
}
private void MultipleChoiceRevealChoice1()
{
HostCardMultipleChoiceInterface Interface =
(HostCardMultipleChoiceInterface)GetHostCardInterface(QuestionType.MultipleChoice);
Interface.ChoiceButtonImages[0].color = (_QuestionCorrectResponse == 1) ? Color.green : Color.red;
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.As5);
EnableInteraction("Reveal Choice 2");
}
private void MultipleChoiceRevealChoice2()
{
HostCardMultipleChoiceInterface Interface =
(HostCardMultipleChoiceInterface)GetHostCardInterface(QuestionType.MultipleChoice);
Interface.ChoiceButtonImages[1].color = (_QuestionCorrectResponse == 2) ? Color.green : Color.red;
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.C6);
EnableInteraction("Reveal Choice 3");
}
private void MultipleChoiceRevealChoice3()
{
HostCardMultipleChoiceInterface Interface =
(HostCardMultipleChoiceInterface)GetHostCardInterface(QuestionType.MultipleChoice);
Interface.ChoiceButtonImages[2].color = (_QuestionCorrectResponse == 3) ? Color.green : Color.red;
DataList Choices = _CurrentQuestion["Choices"].DataList;
EnableChoiceCards();
// Complex per-podium randomiser, to prevent peeking
Random.InitState(Networking.GetServerTimeInMilliseconds());
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
int[] Indices = { 0, 1, 2 };
int[] ChoiceOrder = { -1, -1, -1 };
int Choice1Index = Indices[Random.Range(0, 3)];
ChoiceOrder[0] = Choice1Index;
Indices[Choice1Index] = -1;
int Choice2Index = -1;
while (Choice2Index == -1) { Choice2Index = Indices[Random.Range(0, 3)]; }
ChoiceOrder[1] = Choice2Index;
Indices[Choice2Index] = -1;
int Choice3Index = -1;
while (Choice3Index == -1) { Choice3Index = Indices[Random.Range(0, 3)]; }
ChoiceOrder[2] = Choice3Index;
Indices[Choice3Index] = -1;
string[] ChoiceStrings = { Choices[0].ToString(), Choices[1].ToString(), Choices[2].ToString() };
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "SetCardChoices", ChoiceStrings, ChoiceOrder);
}
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.D6);
EnableInteraction("Lock Answers");
}
private void MultipleChoiceLockAnswers()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "LockInChoice");
}
HostCardMultipleChoiceInterface Interface =
(HostCardMultipleChoiceInterface)GetHostCardInterface(QuestionType.MultipleChoice);
Interface.HeaderUI.text = "LOCKED IN";
for (int i = 0; i < Interface.CluesUI.Length; i++)
{
Interface.CluesUI[i].text = "";
}
for (int i = 0; i < Interface.ChoiceUI.Length; i++)
{
if (i != (_QuestionCorrectResponse - 1))
{
Interface.ChoiceUI[i].text = "";
}
}
EnableInteraction("Reveal Answers And Assign Points");
}
private void MultipleChoiceRevealAnswersAndAssignPoints()
{
HostCardMultipleChoiceInterface Interface =
(HostCardMultipleChoiceInterface)GetHostCardInterface(QuestionType.MultipleChoice);
Interface.HeaderUI.text = "ANSWER REVEALED";
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[i],
NetworkEventTarget.All,
"VerifyMultipleChoiceResponse", _QuestionCorrectResponse);
}
EnableInteraction("Next Question");
}
private void BeginLightningRound()
{
HostCardLightningRoundInterface Interface =
(HostCardLightningRoundInterface)GetHostCardInterface(QuestionType.LightningRound);
Interface.HeaderUI.text = QuestionTypeToString((QuestionType)((int)_CurrentQuestion["Type"].Number)) + " | " + _CurrentQuestion["Location"].ToString();
for (int i = 0; i < Interface.ChoiceUI.Length && i < Interface.ChoiceButtons.Length; i++)
{
Interface.ChoiceUI[i].text = "";
}
Interface.QuestionUI.text = "All of these questions are worth 5 Acme Crimebucks. These questions are all about [[CROOK]]'s most recent whereabouts, which is " + _CurrentQuestion["Location"].ToString() + ". Hands on your buzzers. Here's the first question...";
EnableBuzzers();
EnableInteraction("First Question");
}
private void NewLightningRoundQuestion(int Question)
{
DataDictionary CurrentQuestion = _CurrentQuestion["Questions"].DataList[Question - 1].DataDictionary;
HostCardLightningRoundInterface Interface =
(HostCardLightningRoundInterface)GetHostCardInterface(QuestionType.LightningRound);
Interface.QuestionUI.text = CurrentQuestion["Question"].ToString();
DataList Choices = CurrentQuestion["Choices"].DataList;
for (int i = 0; i < Choices.Count && i < Interface.ChoiceUI.Length; i++)
{
Interface.ChoiceUI[i].text = Choices[i].ToString();
}
_QuestionCorrectResponse = (int)CurrentQuestion["Correct Response"].Number;
for (int i = 0; i < Interface.ChoiceButtons.Length && i < Interface.ChoiceButtonImages.Length; i++)
{
Interface.ChoiceButtonImages[i].color = (_QuestionCorrectResponse == (i + 1)) ? Color.green : Color.red;
Interface.ChoiceButtons[i].interactable = true;
}
Interface.OtherButton.interactable = true;
EnableBuzzInPeriodForAllPlayers();
}
private void LightningRoundCheckAnswer(int Answer)
{
if (_QuestionCorrectResponse == Answer)
{
HostCardLightningRoundInterface Interface =
(HostCardLightningRoundInterface)GetHostCardInterface(QuestionType.LightningRound);
for (int i = 0; i < Interface.ChoiceButtons.Length; i++)
{
Interface.ChoiceButtons[i].interactable = false;
}
Interface.OtherButton.interactable = false;
int PodiumIndex = _BuzzedInPlayer - 1;
if (PodiumIndex >= 0 && PodiumIndex < _PlayerPodiums.Length)
{
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[PodiumIndex],
NetworkEventTarget.All,
"AdjustScore", 5);
}
EndBuzzInPeriod();
EnableInteraction("Next Question");
}
else
{
WaitForBuzzInsWithoutLastPlayer();
}
}
public void LightningRoundCheckAnswer1()
{
LightningRoundCheckAnswer(1);
}
public void LightningRoundCheckAnswer2()
{
LightningRoundCheckAnswer(2);
}
public void LightningRoundCheckAnswer3()
{
LightningRoundCheckAnswer(3);
}
public void LightningRoundOtherOptionChosen()
{
WaitForBuzzInsWithoutLastPlayer();
}
private void BeginTheChase()
{
HostCardTheChaseInterface Interface =
(HostCardTheChaseInterface)GetHostCardInterface(QuestionType.TheChase);
Interface.HeaderUI.text = QuestionTypeToString((QuestionType)((int)_CurrentQuestion["Type"].Number));
Interface.ClueUI.text = "";
for (int i = 0; i < Interface.ChoiceUI.Length && i < Interface.ChoiceButtons.Length; i++)
{
Interface.ChoiceUI[i].text = "";
}
EnableBuzzers();
EnableInteraction("Play The Music");
}
private void PlayTheChaseMusic()
{
HostCardTheChaseInterface Interface =
(HostCardTheChaseInterface)GetHostCardInterface(QuestionType.TheChase);
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlayMusic", MusicEventType.TheChase);
Interface.HeaderUI.text = QuestionTypeToString(QuestionType.TheChase);
Interface.ClueUI.text = "All of these questions are worth 5 Acme Crimebucks. Hands on your buzzers. Listen carefully. Here we go.";
EnableBuzzers();
EnableInteraction("Here We Go");
}
private void NewTheChaseClue(int Clue)
{
DataDictionary CurrentClue = _CurrentQuestion["Clues"].DataList[Clue - 1].DataDictionary;
HostCardTheChaseInterface Interface =
(HostCardTheChaseInterface)GetHostCardInterface(QuestionType.TheChase);
Interface.ClueUI.text = CurrentClue["Clue"].ToString();
DataList Choices = CurrentClue["Choices"].DataList;
for (int i = 0; i < Choices.Count && i < Interface.ChoiceUI.Length; i++)
{
Interface.ChoiceUI[i].text = Choices[i].ToString();
}
Interface.OtherButton.interactable = true;
_QuestionCorrectResponse = (int)CurrentClue["Correct Response"].Number;
for (int i = 0; i < Interface.ChoiceButtons.Length && i < Interface.ChoiceButtonImages.Length; i++)
{
Interface.ChoiceButtonImages[i].color = (_QuestionCorrectResponse == (i + 1)) ? Color.green : Color.red;
Interface.ChoiceButtons[i].interactable = true;
}
EnableBuzzInPeriodForAllPlayers();
}
private void TheChaseCheckAnswer(int Answer)
{
Debug.LogError("Answer is " + Answer + ", correct response is " + _QuestionCorrectResponse);
if (_QuestionCorrectResponse == Answer)
{
int PodiumIndex = _BuzzedInPlayer - 1;
if (PodiumIndex >= 0 && PodiumIndex < _PlayerPodiums.Length)
{
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[PodiumIndex],
NetworkEventTarget.All,
"AdjustScore", 5);
}
}
TheChaseEndClue();
}
public void TheChaseCheckAnswer1()
{
TheChaseCheckAnswer(1);
}
public void TheChaseCheckAnswer2()
{
TheChaseCheckAnswer(2);
}
public void TheChaseCheckAnswer3()
{
TheChaseCheckAnswer(3);
}
public void TheChaseEndClue()
{
HostCardTheChaseInterface Interface =
(HostCardTheChaseInterface)GetHostCardInterface(QuestionType.TheChase);
for (int i = 0; i < Interface.ChoiceButtons.Length; i++)
{
Interface.ChoiceButtons[i].interactable = false;
}
Interface.OtherButton.interactable = false;
EndBuzzInPeriod();
EnableInteraction("Next Question");
}
private void BeginFinalRound()
{
HostCardFinalRoundInterface Interface =
(HostCardFinalRoundInterface)GetHostCardInterface(QuestionType.FinalRound);
Interface.HeaderUI.text = QuestionTypeToString((QuestionType)((int)_CurrentQuestion["Type"].Number)) + " | Showing Map Preview";
EnableRiskCards();
DataList ClueStrings = _CurrentQuestion["Clues"].DataList;
for (int i = 0; i < Interface.CluesUI.Length && i < ClueStrings.Count; i++)
{
Interface.CluesUI[i].text = ClueStrings[i].ToString();
}
DataList Choices = _CurrentQuestion["Choices"].DataList;
for (int i = 0; i < Choices.Count && i < Interface.ChoiceUI.Length; i++)
{
Interface.ChoiceUI[i].text = Choices[i].ToString();
}
_QuestionCorrectResponse = (int)_CurrentQuestion["Correct Response"].Number;
EnableInteraction("Think About It");
}
private void PlayThinkingMusic()
{
HostCardBetweenRoundsInterface Interface =
(HostCardBetweenRoundsInterface)GetHostCardInterface(QuestionType.BetweenRounds);
Interface.HeaderUI.text = "Think about it...";
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlayMusic", MusicEventType.ThinkAboutIt);
SendCustomEventDelayedSeconds(nameof(ThinkAboutItCountdownFinished), 15.0f);
}
public void ThinkAboutItCountdownFinished()
{
GetHostCardInterface(QuestionType.FinalRound);
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "LockInRisk");
}
EnableInteraction("Reveal Choice 1");
}
private void FinalRoundRevealChoices()
{
SendCustomEvent(nameof(FinalRoundRevealChoice1));
SendCustomEventDelayedSeconds(nameof(FinalRoundRevealChoice2), 1.25f);
SendCustomEventDelayedSeconds(nameof(FinalRoundRevealChoice3), 2.5f);
}
private void FinalRoundRevealChoice1()
{
HostCardFinalRoundInterface Interface =
(HostCardFinalRoundInterface)GetHostCardInterface(QuestionType.FinalRound);
Interface.ChoiceButtonImages[0].color = (_QuestionCorrectResponse == 1) ? Color.green : Color.red;
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.As5);
EnableInteraction("Reveal Choice 2");
}
private void FinalRoundRevealChoice2()
{
HostCardFinalRoundInterface Interface =
(HostCardFinalRoundInterface)GetHostCardInterface(QuestionType.FinalRound);
Interface.ChoiceButtonImages[1].color = (_QuestionCorrectResponse == 2) ? Color.green : Color.red;
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.C6);
EnableInteraction("Reveal Choice 3");
}
private void FinalRoundRevealChoice3()
{
HostCardFinalRoundInterface Interface =
(HostCardFinalRoundInterface)GetHostCardInterface(QuestionType.FinalRound);
Interface.ChoiceButtonImages[2].color = (_QuestionCorrectResponse == 3) ? Color.green : Color.red;
DataList Choices = _CurrentQuestion["Choices"].DataList;
EnableChoiceCards();
// Complex per-podium randomiser, to prevent peeking
Random.InitState(Networking.GetServerTimeInMilliseconds());
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
int[] Indices = { 0, 1, 2 };
int[] ChoiceOrder = { -1, -1, -1 };
int Choice1Index = Indices[Random.Range(0, 3)];
ChoiceOrder[0] = Choice1Index;
Indices[Choice1Index] = -1;
int Choice2Index = -1;
while (Choice2Index == -1) { Choice2Index = Indices[Random.Range(0, 3)]; }
ChoiceOrder[1] = Choice2Index;
Indices[Choice2Index] = -1;
int Choice3Index = -1;
while (Choice3Index == -1) { Choice3Index = Indices[Random.Range(0, 3)]; }
ChoiceOrder[2] = Choice3Index;
Indices[Choice3Index] = -1;
string[] ChoiceStrings = { Choices[0].ToString(), Choices[1].ToString(), Choices[2].ToString() };
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "SetCardChoices", ChoiceStrings, ChoiceOrder);
}
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.D6);
EnableInteraction("Lock Answers");
}
private void FinalRoundLockAnswers()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "LockInChoice");
}
HostCardFinalRoundInterface Interface =
(HostCardFinalRoundInterface)GetHostCardInterface(QuestionType.FinalRound);
Interface.HeaderUI.text = "LOCKED IN";
for (int i = 0; i < Interface.CluesUI.Length; i++)
{
Interface.CluesUI[i].text = "";
}
for (int i = 0; i < Interface.ChoiceUI.Length; i++)
{
if (i != (_QuestionCorrectResponse - 1))
{
Interface.ChoiceUI[i].text = "";
}
}
SortPlayersHighToLowScore();
EnableInteraction("Reveal Third Place");
}
private void SortPlayersHighToLowScore()
{
int PlayerPodiumsCount = _PlayerPodiums.Length;
// We're gonna pull a trick here that lets us sort the scores and
// players properly. By multiplying the score by 1000 and then adding
// the player number to it, we can easily sort by score, followed by
// player number, and then convert that back to the needed information
// later. We also store the inverse player number (1000 - player no.)
// so that they are sorted in the opposite order they normally would
// when scores are equal, ensuring that if there is a 3-way tie, the
// order will still be Player 1 -> Player 2 -> Player 3.
DataList ScoresList = new DataList();
for (int i = 0; i < PlayerPodiumsCount; i++)
{
ScoresList.Add(((_PlayerPodiums[i].PlayerScore) * 1000) + (1000 - _PlayerPodiums[i].PlayerNumber));
}
ScoresList.Sort();
_FinalRoundPlayersSortedByScore = new int[ScoresList.Count];
for (int i = 0; i < _FinalRoundPlayersSortedByScore.Length; i++)
{
int DecodedPlayerNumber = 1000 - (ScoresList[i].Int % 1000);
_FinalRoundPlayersSortedByScore[_FinalRoundPlayersSortedByScore.Length - i - 1] = DecodedPlayerNumber;
}
}
private void FinalRoundRevealPlayerPlace(int PlayerPlace)
{
int PlayerNumber = _FinalRoundPlayersSortedByScore[PlayerPlace - 1];
HostCardBetweenRoundsInterface Interface =
(HostCardBetweenRoundsInterface)GetHostCardInterface(QuestionType.BetweenRounds);
Interface.HeaderUI.text = "Player: " + _PlayerPodiums[PlayerNumber - 1].PlayerName;
_PlayerPodiums[PlayerNumber - 1].EnableBuzzInEffect(true);
EnableInteraction("Assign Points");
}
private void FinalRoundAssignPointsToPlayerPlace(int PlayerPlace)
{
int PlayerNumber = _FinalRoundPlayersSortedByScore[PlayerPlace - 1];
_PlayerPodiums[PlayerNumber - 1].EnableBuzzInEffect(false);
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[PlayerNumber - 1],
NetworkEventTarget.All,
"VerifyFinalRoundResponse", _QuestionCorrectResponse);
// If we're assigning points to the first-place player, then we're
// about to finish up, so just move on to determining winners.
if (PlayerPlace == 1)
{
FinalRoundDetermineWinners();
}
else
{
EnableInteraction("Reveal Next Player Answer");
}
}
private void FinalRoundDetermineWinners()
{
SortPlayersHighToLowScore();
int[] SortedPlayerScores = new int[_PlayerPodiums.Length];
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
SortedPlayerScores[i] = _PlayerPodiums[_FinalRoundPlayersSortedByScore[i] - 1].PlayerScore;
}
HostCardBetweenRoundsInterface Interface =
(HostCardBetweenRoundsInterface)GetHostCardInterface(QuestionType.BetweenRounds);
bool TiebreakerNeeded = false;
if (SortedPlayerScores[1] == SortedPlayerScores[2])
{
if (SortedPlayerScores[0] == SortedPlayerScores[1])
{
Interface.HeaderUI.text = "Three-way tie; two tiebreakers will appear here in the final version.";
}
else
{
Interface.HeaderUI.text = "Tie for second place between [[PLAYER]] and [[PLAYER]]; tiebreaker will appear here in the final version.";
}
TiebreakerNeeded = true;
}
else
{
VRCPlayerApi Number1 = Networking.GetOwner(_PlayerPodiums[_FinalRoundPlayersSortedByScore[0] - 1].gameObject);
VRCPlayerApi Number2 = Networking.GetOwner(_PlayerPodiums[_FinalRoundPlayersSortedByScore[1] - 1].gameObject);
if (SortedPlayerScores[0] == SortedPlayerScores[1])
{
// Tag both players as being tied for first place
Number1.SetPlayerTag("Round1State", "TiedForFirstPlace");
Number2.SetPlayerTag("Round2State", "TiedForFirstPlace");
Interface.HeaderUI.text = "[[PLAYER]] and [[PLAYER]] are tied for first; both will move on to the next round.";
}
else
{
// Tag first place player as first place, and second place as second
Number1.SetPlayerTag("Round1State", "FirstPlace");
Number2.SetPlayerTag("Round2State", "SecondPlace");
Interface.HeaderUI.text = "[[FIRSTPLACEPLAYER]] and [[SECONDPLACEPLAYER]] will move on to the next round.";
}
}
if (TiebreakerNeeded)
{
EnableInteraction("Advance To Tiebreaker");
}
else
{
EnableInteraction("End Game");
}
}
private void AdvanceToNextQuestion()
{
DisableChoiceCards();
DisableRiskCards();
DisableBuzzers();
HostCardBetweenRoundsInterface Interface =
(HostCardBetweenRoundsInterface)GetHostCardInterface(QuestionType.BetweenRounds);
_QuestionIndex++;
if (_QuestionIndex >= _QuestionsList.Count)
{
Interface.HeaderUI.text = "Round is over. Move to the loot recovery area.";
_CaseManager.ContinueToRound2();
return;
}
_CurrentQuestion = _QuestionsList[_QuestionIndex].DataDictionary;
_QuestionStage = 0;
// Again, why does this work, but not just casting to an enum?
Interface.HeaderUI.text = "Upcoming Question: " + QuestionTypeToString((QuestionType)((int)_CurrentQuestion["Type"].Number));
EnableInteraction("Show Next Question");
}
private void ResetMultipleChoiceInterface(HostCardMultipleChoiceInterface Interface)
{
Interface.HeaderUI.text = "";
for (int i = 0; i < Interface.CluesUI.Length; i++)
{
Interface.CluesUI[i].text = "";
}
for (int i = 0; i < Interface.ChoiceButtonImages.Length; i++)
{
Interface.ChoiceButtonImages[i].color = Color.white;
}
for (int i = 0; i < Interface.ChoiceUI.Length; i++)
{
Interface.ChoiceUI[i].text = "";
}
}
private void EnableChoiceCards()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableChoiceCards", true);
}
}
private void DisableChoiceCards()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableChoiceCards", false);
}
}
private void EnableRiskCards()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableRiskCards", true);
}
}
private void DisableRiskCards()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableRiskCards", false);
}
}
private void EnableBuzzers()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableBuzzer", true);
}
}
private void DisableBuzzers()
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableBuzzer", false);
}
}
private void EnableBuzzInPeriodForAllPlayers()
{
_BuzzInAllowed = true;
ResetBuzzers();
}
private void WaitForBuzzInsWithoutLastPlayer() {
_BuzzInAllowed = true;
int PodiumIndex = _BuzzedInPlayer - 1;
if (PodiumIndex >= 0 && PodiumIndex < _PlayerPodiums.Length)
{
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[_BuzzedInPlayer - 1],
NetworkEventTarget.All,
"EnableBuzzInEffect", false);
_BuzzedInPlayer = -1;
RequestSerialization();
}
}
[NetworkCallable]
public void PlayerBuzzedIn(int PlayerNumber)
{
int PlayerIndex = PlayerNumber - 1;
if (!_BuzzInAllowed || !_PlayerBuzzInAllowed[PlayerIndex]) { return; }
// Prevent new buzz-ins and store which player is currently buzzed in.
_BuzzInAllowed = false;
_PlayerBuzzInAllowed[PlayerIndex] = false;
_BuzzedInPlayer = PlayerNumber;
RequestSerialization();
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[PlayerIndex],
NetworkEventTarget.All,
"EnableBuzzInEffect", true);
// Play the buzzer sound globally.
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFX", SFXEventType.Buzzer);
}
private void EndBuzzInPeriod()
{
_BuzzInAllowed = false;
ResetBuzzers();
}
private void ResetBuzzers()
{
for (int i = 0; i < _PlayerPodiums.Length; i++) {
_PlayerBuzzInAllowed[i] = true;
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_PlayerPodiums[i], NetworkEventTarget.All, "EnableBuzzInEffect", false);
}
_BuzzedInPlayer = -1;
}
private void AdvanceQuestion()
{
// Disable interaction until we unlock it again later.
DisableInteraction();
_QuestionStage++;
// TO-DO: Ask someone at either Microsoft or VRChat why the VM crashes if you cast an int
// to an enum in a switch parameter, but not if you cast an enum to an int in a case
// statement. I'm starting to wonder if either C# or U# are just fucking terrible
// languages. C++ figured this problem out in at least 1985, and it turns out the proper
// solution was "it's not a problem, it's two numbers, they're the same fucking thing".
switch ((int)_CurrentQuestion["Type"].Number)
{
case (int)QuestionType.MultipleChoice: AdvanceMultipleChoiceStage(); break;
case (int)QuestionType.LightningRound: AdvanceLightningRoundQuestion(); break;
case (int)QuestionType.TheChase: AdvanceTheChase(); break;
case (int)QuestionType.FinalRound: AdvanceFinalRound(); break;
}
RequestSerialization();
}
private void AdvanceMultipleChoiceStage()
{
switch(_QuestionStage)
{
case 1: NewMultipleChoiceQuestion(); break;
case 2: MultipleChoiceRevealChoice1(); break;
case 3: MultipleChoiceRevealChoice2(); break;
case 4: MultipleChoiceRevealChoice3(); break;
case 5: MultipleChoiceLockAnswers(); break;
case 6: MultipleChoiceRevealAnswersAndAssignPoints(); break;
case 7: AdvanceToNextQuestion(); break;
default: break;
}
}
private void AdvanceLightningRoundQuestion()
{
switch(_QuestionStage)
{
case 1: BeginLightningRound(); break;
case 2: NewLightningRoundQuestion(1); break;
case 3: NewLightningRoundQuestion(2); break;
case 4: NewLightningRoundQuestion(3); break;
case 5: AdvanceToNextQuestion(); break;
default: break;
}
}
private void AdvanceTheChase()
{
switch(_QuestionStage)
{
case 1: BeginTheChase(); break;
case 2: PlayTheChaseMusic(); break;
case 3: NewTheChaseClue(1); break;
case 4: NewTheChaseClue(2); break;
case 5: NewTheChaseClue(3); break;
case 6: NewTheChaseClue(4); break;
case 7: NewTheChaseClue(5); break;
case 8: AdvanceToNextQuestion(); break;
default: break;
}
}
private void AdvanceFinalRound()
{
switch (_QuestionStage)
{
case 1: BeginFinalRound(); break;
case 2: PlayThinkingMusic(); break;
case 3: FinalRoundRevealChoice1(); break;
case 4: FinalRoundRevealChoice2(); break;
case 5: FinalRoundRevealChoice3(); break;
case 6: FinalRoundLockAnswers(); break;
case 7: FinalRoundRevealPlayerPlace(3); break;
case 8: FinalRoundAssignPointsToPlayerPlace(3); break;
case 9: FinalRoundRevealPlayerPlace(2); break;
case 10: FinalRoundAssignPointsToPlayerPlace(2); break;
case 11: FinalRoundRevealPlayerPlace(1); break;
case 12: FinalRoundAssignPointsToPlayerPlace(1); break;
case 13: AdvanceToNextQuestion(); break;
default: break;
}
}
protected override void _HostCardUseButtonDown_Internal()
{
if (!_GameHasBegun)
{
for (int i = 0; i < _PlayerPodiums.Length; i++)
{
NetworkCalling.SendCustomNetworkEvent(
(IUdonEventReceiver)_PlayerPodiums[i],
NetworkEventTarget.All,
"DisplayScore");
}
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)_AudioManager, NetworkEventTarget.All,
"PlaySFXAtPitch", SFXEventType.Ding, AudioManager.D6);
_CurrentQuestion = _QuestionsList[_QuestionIndex].DataDictionary;
HostCardBetweenRoundsInterface Interface =
(HostCardBetweenRoundsInterface)GetHostCardInterface(QuestionType.BetweenRounds);
Interface.HeaderUI.text = "Upcoming Question: " + QuestionTypeToString((QuestionType)((int)_CurrentQuestion["Type"].Number));
_GameHasBegun = true;
return;
}
AdvanceQuestion();
}
protected override HostCardInterfaceBase GetHostCardInterface(QuestionType Question)
{
return _HostCard.EnableHostCardDisplay(GameType.LocateTheCrook, Question);
}
}