Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LethalQuiz v1.0.2
LethalQuiz.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Hura.Patches; using Hura.Project; using Hura.Project.Quiz; using Hura.Project.Utility; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Hura")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("HP")] [assembly: AssemblyProduct("Hura")] [assembly: AssemblyCopyright("Copyright © HP 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("351ddba5-b276-4062-9ba5-e04fb454ffc9")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.2.0")] namespace Hura { [BepInPlugin("Hura.LethalQuiz", "Lethal Quiz", "1.0.2")] public class LethalQuiz : BaseUnityPlugin { private const string MOD_GUID = "Hura.LethalQuiz"; private const string MOD_NAME = "Lethal Quiz"; private const string MOD_VERSION = "1.0.2"; private readonly Harmony harmony = new Harmony("Hura.LethalQuiz"); public static ManualLogSource logger; public static LethalQuiz Instance { get; private set; } private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } logger = Logger.CreateLogSource("Hura.LethalQuiz"); QuizManager.ImportQuiz(); harmony.PatchAll(typeof(LethalQuiz)); harmony.PatchAll(typeof(TerminalHelper)); harmony.PatchAll(typeof(HUDManagerPatch)); harmony.PatchAll(typeof(QuizManager)); } } } namespace Hura.Project { [HarmonyPatch(typeof(HUDManager))] internal class HUDHelper { public static HUDManager HUDManager { get; private set; } [HarmonyPatch("Awake")] [HarmonyPostfix] public static void RegisterTerminalInstance(ref HUDManager __instance) { HUDManager = __instance; } } internal static class HuraHelper { public static PlayerControllerB[] Players => StartOfRound.Instance.allPlayerScripts; } [HarmonyPatch(typeof(Terminal))] public static class TerminalHelper { private static StringBuilder stringBuilder = new StringBuilder(); public static Terminal Terminal { get; private set; } [HarmonyPatch("Awake")] [HarmonyPostfix] public static void RegisterTerminalInstance(ref Terminal __instance) { Terminal = __instance; } public static TerminalNode CreateNode(string text, bool clear = true) { TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>(); obj.displayText = text; obj.clearPreviousText = clear; return obj; } public static TerminalKeyword CreateKeyword(string word, bool isVerb, TerminalNode destinationNode) { TerminalKeyword obj = ScriptableObject.CreateInstance<TerminalKeyword>(); obj.word = word; obj.isVerb = isVerb; obj.specialKeywordResult = destinationNode; return obj; } public static void AddKeyworkToTerminal(TerminalKeyword keyword) { ArrayUtility.Add(ref Terminal.terminalNodes.allKeywords, keyword); } public static string CreateNodeText(params string[] args) { stringBuilder.Clear(); for (int i = 0; i < args.Length; i++) { stringBuilder.Append(args[i]).Append("\n"); } return stringBuilder.ToString(); } public static CompatibleNoun CreateCompatibleNoun(TerminalKeyword noun, TerminalNode destinationNode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown return new CompatibleNoun { noun = noun, result = destinationNode }; } public static void AddCompatibleNounToVerb(TerminalKeyword verb, TerminalKeyword noun, TerminalNode destinationNode) { if (!verb.isVerb) { LethalQuiz.logger.LogError((object)("Error while adding compatible noun to verb. Given verb is not a verb: " + verb.word)); return; } if (noun.isVerb) { LethalQuiz.logger.LogError((object)("Error while adding compatible noun to verb. Given noun is a verb: " + noun.word)); return; } CompatibleNoun element = CreateCompatibleNoun(noun, destinationNode); ArrayUtility.Add(ref verb.compatibleNouns, element); } } } namespace Hura.Project.Utility { internal static class ArrayUtility { public static void Add<T>(ref T[] array, T element) { if (array == null) { array = new T[0]; } Array.Resize(ref array, array.Length + 1); array[array.Length - 1] = element; } } internal static class HuraLinq { private static void ShuffleSelf<T>(this IList<T> list, Func<int, int> randomIndexMethod) { for (int num = list.Count - 1; num > 0; num--) { int index = randomIndexMethod(num); T value = list[num]; list[num] = list[index]; list[index] = value; } } public static void ShuffleSelf<T>(this IList<T> list) { list.ShuffleSelf(RandomIndex); static int RandomIndex(int iterationIndex) { return Random.Range(0, iterationIndex + 1); } } public static void ShuffleSelf<T>(this IList<T> list, Random random) { list.ShuffleSelf(RandomIndex); int RandomIndex(int iterationIndex) { return random.Next(iterationIndex + 1); } } } } namespace Hura.Project.Quiz { internal class FoggyCurse : ICurse { private readonly HashSet<LevelWeatherType> allowedWeather = new HashSet<LevelWeatherType> { (LevelWeatherType)(-1), (LevelWeatherType)0, (LevelWeatherType)1 }; public float Weight => 1f; public void ApplyCurse() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) RoundManager.Instance.currentLevel.currentWeather = (LevelWeatherType)3; ((object)RoundManager.Instance).GetType().GetMethod("SetToCurrentLevelWeather", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(RoundManager.Instance, null); } public bool CanBeApplied() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } return allowedWeather.Contains(instance.currentLevel.currentWeather); } } internal interface ICurse { float Weight { get; } bool CanBeApplied(); void ApplyCurse(); } internal class MoneyCurse : ICurse { public const int CREDITS_LOST = 40; public float Weight => 1f; public void ApplyCurse() { Terminal terminal = TerminalHelper.Terminal; terminal.groupCredits -= 40; TerminalHelper.Terminal.SyncGroupCreditsServerRpc(TerminalHelper.Terminal.groupCredits, TerminalHelper.Terminal.numberOfItemsInDropship); } public bool CanBeApplied() { return true; } } internal class InsultsCurse : ICurse { public float Weight => 0.25f; public void ApplyCurse() { } public bool CanBeApplied() { return true; } } internal class TeleportCurse : ICurse { public float Weight => 1f; public void ApplyCurse() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) List<PlayerControllerB> availablePlayers = GetAvailablePlayers(); int index = Random.Range(0, availablePlayers.Count); PlayerControllerB obj = availablePlayers[index]; availablePlayers.RemoveAt(index); int index2 = Random.Range(0, availablePlayers.Count); PlayerControllerB val = availablePlayers[index2]; availablePlayers.RemoveAt(index2); Vector3 position = ((Component)obj).transform.position; Vector3 position2 = ((Component)val).transform.position; obj.TeleportPlayer(position2, false, 0f, false, true); val.TeleportPlayer(position, false, 0f, false, true); } public bool CanBeApplied() { return GetAvailablePlayers().Count >= 2; } private List<PlayerControllerB> GetAvailablePlayers() { List<PlayerControllerB> list = HuraHelper.Players.ToList(); for (int num = list.Count - 1; num >= 0; num--) { PlayerControllerB val = list[num]; if (val.isPlayerDead) { list.RemoveAt(num); } else if (val.inTerminalMenu) { list.RemoveAt(num); } else if (val.isClimbingLadder) { list.RemoveAt(num); } } return list; } } internal static class CurseManager { private static List<ICurse> curses; static CurseManager() { curses = new List<ICurse>(); curses.Add(new MoneyCurse()); } public static ICurse GetRandomCurse() { List<ICurse> list = new List<ICurse>(); foreach (ICurse curse2 in curses) { if (curse2.CanBeApplied()) { list.Add(curse2); } } foreach (ICurse item in list) { LethalQuiz.logger.LogMessage((object)$"Generating random curse... Available curse: {item.GetType()}"); } float num = 0f; float num2 = 0f; foreach (ICurse item2 in list) { num2 += item2.Weight; } float num3 = Random.Range(0f, num2); list.ShuffleSelf(); for (int i = 0; i < list.Count; i++) { ICurse curse = list[i]; if (i == list.Count - 1) { return curse; } num += curse.Weight; if (num3 < num) { return curse; } } return null; } } internal enum QuizResult { Success, Failure, NoQuiz } internal struct QuizResultInfo { public QuizResult result; public Quiz? quiz; } public struct Quiz { public enum Answer { A, B, C, D } public string question; public string[] answers; public byte rightAnswerIndex; public string RightAnswer => answers[rightAnswerIndex]; public Quiz(string question, string[] answers, byte rightAnswerIndex) { this.question = question; this.answers = answers; this.rightAnswerIndex = rightAnswerIndex; } } internal class QuizImporter { public static List<Quiz> ImportQuiz(string filePath) { List<Quiz> list = new List<Quiz>(); try { using (StreamReader streamReader = new StreamReader(filePath)) { while (!streamReader.EndOfStream) { string[] array = streamReader.ReadLine().Split(new char[1] { ';' }); string question = array[0]; string[] answers = new string[4] { array[1], array[2], array[3], array[4] }; byte rightAnswerIndex = byte.Parse(array[5]); list.Add(new Quiz(question, answers, rightAnswerIndex)); } } LethalQuiz.logger.LogMessage((object)$"Successfuly loaded quiz file {Path.GetFileName(filePath)}. Loaded quiz count: {list.Count}."); } catch (Exception ex) { LethalQuiz.logger.LogError((object)("Error occurred while parsing the CSV: " + ex.Message)); } return list; } public static List<Quiz> ImportAllQuiz() { List<Quiz> list = new List<Quiz>(); string[] directories = Directory.GetDirectories(Paths.PluginPath, "lethalquiz", SearchOption.AllDirectories); LethalQuiz.logger.LogMessage((object)$"Directories found: {directories.Length}. Plugin path = {Paths.PluginPath}"); string[] array = directories; for (int i = 0; i < array.Length; i++) { string[] files = Directory.GetFiles(array[i], "*.csv"); foreach (string filePath in files) { list.AddRange(ImportQuiz(filePath)); } } if (list.Count == 0) { LethalQuiz.logger.LogMessage((object)"No quiz files has been found."); } return list; } } [HarmonyPatch(typeof(Terminal))] internal static class QuizManager { public const string EVENT_ON_START_QUIZ = "quiz.start_quiz"; public const string EVENT_ON_ANSWER_A = "quiz.answer_a"; public const string EVENT_ON_ANSWER_B = "quiz.answer_b"; public const string EVENT_ON_ANSWER_C = "quiz.answer_c"; public const string EVENT_ON_ANSWER_D = "quiz.answer_d"; private const string ATTRIBUTE_QUESTION = "[quiz]"; private const string ATTRIBUTE_ANSWER_A = "[answerA]"; private const string ATTRIBUTE_ANSWER_B = "[answerB]"; private const string ATTRIBUTE_ANSWER_C = "[answerC]"; private const string ATTRIBUTE_ANSWER_D = "[answerD]"; private const string ATTRIBUTE_ANSWER_HELP = "[answerHelp]"; private const string ATTRIBUTE_RESULT = "[quiz_result]"; private const int MONEY_REWARD_AMOUNT = 20; private static StringBuilder builder = new StringBuilder(); private static Random random = new Random(); private static Quiz? currentQuiz; private static QuizResultInfo? currentResult; private static TerminalNode[] answerNodes = (TerminalNode[])(object)new TerminalNode[4]; private static TerminalNode helpNode; private static TerminalNode quizNode; private static TerminalNode answerANode; private static TerminalNode answerBNode; private static TerminalNode answerCNode; private static TerminalNode answerDNode; private static TerminalNode shipPhaseNode; private static List<Quiz> quizList = new List<Quiz>(); [HarmonyPatch("Start")] [HarmonyPostfix] public static void Initialize() { AddQuizCommandsToTerminal(); } public static void ImportQuiz() { quizList = QuizImporter.ImportAllQuiz(); } public static void AddQuizCommandsToTerminal() { helpNode = TerminalHelper.CreateNode(CreateHelpText()); quizNode = TerminalHelper.CreateNode(CreateQuizTextTemplate()); answerANode = TerminalHelper.CreateNode(CreateResultTextTemplate()); answerBNode = TerminalHelper.CreateNode(CreateResultTextTemplate()); answerCNode = TerminalHelper.CreateNode(CreateResultTextTemplate()); answerDNode = TerminalHelper.CreateNode(CreateResultTextTemplate()); shipPhaseNode = TerminalHelper.CreateNode("You cannot start a quiz while in the ship phase."); answerNodes = (TerminalNode[])(object)new TerminalNode[4] { answerANode, answerBNode, answerCNode, answerDNode }; quizNode.terminalEvent = "quiz.start_quiz"; answerANode.terminalEvent = "quiz.answer_a"; answerBNode.terminalEvent = "quiz.answer_b"; answerCNode.terminalEvent = "quiz.answer_c"; answerDNode.terminalEvent = "quiz.answer_d"; TerminalKeyword obj = TerminalHelper.CreateKeyword("quiz", isVerb: true, helpNode); TerminalKeyword val = TerminalHelper.CreateKeyword("start", isVerb: false, null); TerminalKeyword val2 = TerminalHelper.CreateKeyword("answera", isVerb: false, answerANode); TerminalKeyword val3 = TerminalHelper.CreateKeyword("answerb", isVerb: false, answerBNode); TerminalKeyword val4 = TerminalHelper.CreateKeyword("answerc", isVerb: false, answerCNode); TerminalKeyword val5 = TerminalHelper.CreateKeyword("answerd", isVerb: false, answerDNode); TerminalHelper.AddCompatibleNounToVerb(obj, val, quizNode); TerminalHelper.AddCompatibleNounToVerb(obj, val2, answerANode); TerminalHelper.AddCompatibleNounToVerb(obj, val3, answerBNode); TerminalHelper.AddCompatibleNounToVerb(obj, val4, answerCNode); TerminalHelper.AddCompatibleNounToVerb(obj, val5, answerDNode); TerminalHelper.AddKeyworkToTerminal(val); TerminalHelper.AddKeyworkToTerminal(obj); TerminalHelper.AddKeyworkToTerminal(val2); TerminalHelper.AddKeyworkToTerminal(val3); TerminalHelper.AddKeyworkToTerminal(val4); TerminalHelper.AddKeyworkToTerminal(val5); } [HarmonyPatch("TextPostProcess")] [HarmonyPostfix] public static void PostProcessQuizText(ref string __result, string modifiedDisplayText, TerminalNode node) { if (currentQuiz.HasValue) { Quiz value = currentQuiz.Value; __result = __result.Replace("[quiz]", value.question); __result = __result.Replace("[answerA]", "A: " + value.answers[0]); __result = __result.Replace("[answerB]", "B: " + value.answers[1]); __result = __result.Replace("[answerC]", "C: " + value.answers[2]); __result = __result.Replace("[answerD]", "D: " + value.answers[3]); __result = __result.Replace("[answerHelp]", "Reply with \"answera\", \"answerb\"..."); } if (currentResult.HasValue) { QuizResultInfo value2 = currentResult.Value; switch (value2.result) { case QuizResult.Success: __result = __result.Replace("[quiz_result]", TerminalHelper.CreateNodeText("Good Answer!", "", $"You have earned {20}$.")); break; case QuizResult.Failure: __result = __result.Replace("[quiz_result]", TerminalHelper.CreateNodeText("Bad Answer!", "", $"The correct answer was {value2.quiz.Value.RightAnswer}. You have lost {40}$.")); break; case QuizResult.NoQuiz: __result = __result.Replace("[quiz_result]", TerminalHelper.CreateNodeText("No quiz has started yet. Use \"quiz start\" to start a quiz.")); break; } } else { __result = __result.Replace("[quiz_result]", TerminalHelper.CreateNodeText("No quiz has started yet. Use \"quiz start\" to start a quiz.")); } } [HarmonyPatch("RunTerminalEvents")] [HarmonyPostfix] public static void RunQuizTerminalEvents(TerminalNode node) { if (!string.IsNullOrEmpty(node.terminalEvent)) { switch (node.terminalEvent) { case "quiz.start_quiz": OnStartQuiz(); break; case "quiz.answer_a": OnAnswerA(); break; case "quiz.answer_b": OnAnswerB(); break; case "quiz.answer_c": OnAnswerC(); break; case "quiz.answer_d": OnAnswerD(); break; } } } [HarmonyPatch("ParsePlayerSentence")] [HarmonyPostfix] private static void ParsePlayerSentence(ref TerminalNode __result) { if (StartOfRound.Instance.inShipPhase && ((Object)(object)__result == (Object)(object)quizNode || answerNodes.Contains(__result))) { __result = shipPhaseNode; } } [HarmonyPatch(typeof(StartOfRound), "ShipLeave")] [HarmonyPostfix] private static void ResetQuizWhenShipLeave() { currentQuiz = null; } private static void OnStartQuiz() { if (!currentQuiz.HasValue) { currentQuiz = GetRandomQuiz(); } ResetCurrentResult(); } private static Quiz GetRandomQuiz() { int index = random.Next(quizList.Count); return quizList[index]; } private static void OnAnswerA() { OnAnswer(0); } private static void OnAnswerB() { OnAnswer(1); } private static void OnAnswerC() { OnAnswer(2); } private static void OnAnswerD() { OnAnswer(3); } private static void OnAnswer(int answerIndex) { QuizResultInfo value; if (!currentQuiz.HasValue) { value = default(QuizResultInfo); value.result = QuizResult.NoQuiz; currentResult = value; return; } QuizResult quizResult = ((currentQuiz.Value.rightAnswerIndex != answerIndex) ? QuizResult.Failure : QuizResult.Success); value = default(QuizResultInfo); value.quiz = currentQuiz; value.result = quizResult; currentResult = value; switch (quizResult) { case QuizResult.Success: OnCorrectAnswer(); break; case QuizResult.Failure: OnWrongAnswer(); break; } ResetCurrentQuiz(); } private static void OnCorrectAnswer() { HUDManager.Instance.UIAudio.PlayOneShot(HUDManager.Instance.displayCollectedScrapSFX); Terminal terminal = TerminalHelper.Terminal; terminal.groupCredits += 20; TerminalHelper.Terminal.SyncGroupCreditsServerRpc(TerminalHelper.Terminal.groupCredits, TerminalHelper.Terminal.numberOfItemsInDropship); } private static void OnWrongAnswer() { HUDManager.Instance.UIAudio.PlayOneShot(HUDManager.Instance.levelIncreaseSFX); LaunchRandomBadThing(); } private static void LaunchRandomBadThing() { ICurse randomCurse = CurseManager.GetRandomCurse(); randomCurse.ApplyCurse(); LethalQuiz.logger.LogMessage((object)$"Curse applied: {randomCurse.GetType()}"); } public static Quiz.Answer ParseAnswer(TerminalNode nodeResult) { for (int i = 0; i < 4; i++) { if ((Object)(object)answerNodes[i] == (Object)(object)nodeResult) { return (Quiz.Answer)i; } } LethalQuiz.logger.LogError((object)"Error while parsing answer with given node. Given node was not one of the answer's node."); return Quiz.Answer.A; } public static TerminalNode CreateQuizNode(Quiz quiz) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown return new TerminalNode { displayText = CreateQuizTextTemplate() }; } private static string CreateHelpText() { return TerminalHelper.CreateNodeText("Welcome to the Lethal Quiz mod!", "", "Answer to questions to gain money. Be careful some bad things can happen if you give the right answer...", "", "To start a quiz, type \"quiz start\". Then answer with \"answera\" for answer A, \"answerb\" for answer B...", "", ""); } private static string CreateQuizTextTemplate() { builder.Clear(); builder.Append("[quiz]").Append("\n").Append("\n") .Append("[answerA]") .Append("\n") .Append("[answerB]") .Append("\n") .Append("[answerC]") .Append("\n") .Append("[answerD]") .Append("\n") .Append("\n\n") .Append("[answerHelp]") .Append("\n") .Append("\n\n"); return builder.ToString(); } private static string CreateResultTextTemplate() { builder.Clear(); builder.Append("[quiz_result]").Append("\n").Append("\n\n"); return builder.ToString(); } private static void ResetCurrentQuiz() { currentQuiz = null; } private static void ResetCurrentResult() { currentResult = null; } } } namespace Hura.Patches { [HarmonyPatch(typeof(HUDManager))] internal class HUDManagerPatch { [HarmonyPatch("ApplyPenalty")] [HarmonyPrefix] private static void NoMoneyLossPatch(ref int playersDead, ref int bodiesInsured) { } } }