Decompiled source of MageArenaPortuguese v1.0.2

MageArenaPortuguese.dll

Decompiled a day ago
using System;
using System.Collections;
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 BepInEx;
using BepInEx.Logging;
using Dissonance;
using HarmonyLib;
using MageArenaPortuguese.Config;
using MageArenaPortugueseVoiceMod;
using Recognissimo;
using Recognissimo.Components;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("MageArenaSpanish")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MageArenaSpanish")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("87fca07c-36fd-431f-b9bf-5a2d6252e2ad")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace MageArenaPortugueseVoice.Patches
{
	[HarmonyPatch(typeof(VoiceControlListener))]
	public static class VoiceControlListenerPatch
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass13_0
		{
			public VoiceControlListener instance;

			internal void <CoResetMicLong>b__0(Result res)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					tryresultMethod.Invoke(instance, new object[1] { res.text ?? string.Empty });
				}
				catch (Exception ex)
				{
					MageArenaPortugueseMod.Log.LogError((object)("Error invoking tryresult (resetmiclong): " + ex));
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass1_0
		{
			public VoiceControlListener __instance;

			internal void <CoWaitGetPlayer>b__0(Result r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					tryresultMethod.Invoke(__instance, new object[1] { r.text ?? string.Empty });
				}
				catch (Exception ex)
				{
					MageArenaPortugueseMod.Log.LogError((object)("Error invoking tryresult: " + ex));
				}
			}
		}

		[CompilerGenerated]
		private sealed class <CoResetMicLong>d__13 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VoiceControlListener instance;

			private <>c__DisplayClass13_0 <>8__1;

			private SpeechRecognizer <oldSr>5__2;

			private SpeechRecognizer <newSr>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CoResetMicLong>d__13(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<oldSr>5__2 = null;
				<newSr>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Expected O, but got Unknown
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Expected O, but got Unknown
				//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_02af: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass13_0();
					<>8__1.instance = instance;
					<oldSr>5__2 = GetOrBindSpeechRecognizer(<>8__1.instance);
					if ((Object)(object)<oldSr>5__2 != (Object)null)
					{
						try
						{
							((SpeechProcessor)<oldSr>5__2).StopProcessing();
						}
						catch (ObjectDisposedException)
						{
						}
						catch (Exception ex2)
						{
							MageArenaPortugueseMod.Log.LogInfo((object)("StopProcessing old SR: " + ex2.Message));
						}
					}
					try
					{
						SrField?.SetValue(<>8__1.instance, null);
					}
					catch
					{
					}
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)<oldSr>5__2 != (Object)null)
					{
						Object.Destroy((Object)(object)<oldSr>5__2);
					}
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 2;
					return true;
				case 2:
				{
					<>1__state = -1;
					<newSr>5__3 = ((Component)<>8__1.instance).gameObject.AddComponent<SpeechRecognizer>();
					try
					{
						SrField?.SetValue(<>8__1.instance, <newSr>5__3);
					}
					catch
					{
					}
					DissonanceSpeechSource speechSource = ((Component)<>8__1.instance).GetComponent<DissonanceSpeechSource>() ?? ((Component)<>8__1.instance).gameObject.AddComponent<DissonanceSpeechSource>();
					((SpeechProcessor)<newSr>5__3).SpeechSource = (SpeechSource)(object)speechSource;
					StreamingAssetsLanguageModelProvider val = ((Component)<>8__1.instance).GetComponent<StreamingAssetsLanguageModelProvider>() ?? ((Component)<>8__1.instance).gameObject.AddComponent<StreamingAssetsLanguageModelProvider>();
					val.language = (SystemLanguage)28;
					val.languageModels = new List<StreamingAssetsLanguageModel>
					{
						new StreamingAssetsLanguageModel
						{
							language = (SystemLanguage)28,
							path = "LanguageModels/" + modelName
						}
					};
					((SpeechProcessor)<newSr>5__3).LanguageModelProvider = (LanguageModelProvider)(object)val;
					<newSr>5__3.Vocabulary = new List<string>();
					addSpellsToVocabulary(<newSr>5__3);
					if (<>8__1.instance.SpellPages != null)
					{
						foreach (ISpellCommand spellPage in <>8__1.instance.SpellPages)
						{
							if (spellPage != null)
							{
								spellPage.ResetVoiceDetect();
							}
						}
					}
					((UnityEventBase)<newSr>5__3.ResultReady).RemoveAllListeners();
					((UnityEvent<Result>)(object)<newSr>5__3.ResultReady).AddListener((UnityAction<Result>)delegate(Result res)
					{
						//IL_0013: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							tryresultMethod.Invoke(<>8__1.instance, new object[1] { res.text ?? string.Empty });
						}
						catch (Exception ex3)
						{
							MageArenaPortugueseMod.Log.LogError((object)("Error invoking tryresult (resetmiclong): " + ex3));
						}
					});
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 3;
					return true;
				}
				case 3:
					<>1__state = -1;
					((SpeechProcessor)<newSr>5__3).StartProcessing();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <CoRestartSr>d__10 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VoiceControlListener inst;

			private SpeechRecognizer <sr>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CoRestartSr>d__10(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<sr>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<sr>5__2 = GetOrBindSpeechRecognizer(inst);
					if ((Object)(object)<sr>5__2 == (Object)null)
					{
						return false;
					}
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if ((int)((SpeechProcessor)<sr>5__2).State != 0)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				((SpeechProcessor)<sr>5__2).StartProcessing();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <CoWaitGetPlayer>d__1 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VoiceControlListener __instance;

			private <>c__DisplayClass1_0 <>8__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CoWaitGetPlayer>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ef: Expected O, but got Unknown
				//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b7: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass1_0();
					<>8__1.__instance = __instance;
					goto IL_00b0;
				case 1:
					<>1__state = -1;
					goto IL_00b0;
				case 2:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					(((Component)<>8__1.__instance).GetComponent<SetUpModelProvider>() ?? ((Component)<>8__1.__instance).gameObject.AddComponent<SetUpModelProvider>()).Setup();
					<>2__current = null;
					<>1__state = 4;
					return true;
				case 4:
				{
					<>1__state = -1;
					SpeechRecognizer orBindSpeechRecognizer2 = GetOrBindSpeechRecognizer(<>8__1.__instance);
					if ((Object)(object)orBindSpeechRecognizer2 == (Object)null)
					{
						MageArenaPortugueseMod.Log.LogError((object)"SpeechRecognizer not found.");
						return false;
					}
					addSpellsToVocabulary(orBindSpeechRecognizer2);
					((UnityEventBase)orBindSpeechRecognizer2.ResultReady).RemoveAllListeners();
					((UnityEvent<Result>)(object)orBindSpeechRecognizer2.ResultReady).AddListener((UnityAction<Result>)delegate(Result r)
					{
						//IL_0013: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							tryresultMethod.Invoke(<>8__1.__instance, new object[1] { r.text ?? string.Empty });
						}
						catch (Exception ex2)
						{
							MageArenaPortugueseMod.Log.LogError((object)("Error invoking tryresult: " + ex2));
						}
					});
					((SpeechProcessor)orBindSpeechRecognizer2).StartProcessing();
					break;
				}
				case 5:
					{
						<>1__state = -1;
						VoiceBroadcastTrigger orBindVbt = GetOrBindVbt(<>8__1.__instance);
						SpeechRecognizer orBindSpeechRecognizer = GetOrBindSpeechRecognizer(<>8__1.__instance);
						if ((Object)(object)orBindSpeechRecognizer != (Object)null && (Object)(object)orBindVbt != (Object)null && !orBindVbt.IsTransmitting)
						{
							try
							{
								((SpeechProcessor)orBindSpeechRecognizer).StopProcessing();
							}
							catch (ObjectDisposedException)
							{
							}
							((MonoBehaviour)<>8__1.__instance).StartCoroutine((IEnumerator)restartsrMethod.Invoke(<>8__1.__instance, null));
						}
						break;
					}
					IL_00b0:
					if ((Object)(object)<>8__1.__instance.pi == (Object)null)
					{
						PlayerInventory pi = default(PlayerInventory);
						if ((Object)(object)Camera.main != (Object)null && (Object)(object)((Component)Camera.main).transform.parent != (Object)null && ((Component)((Component)Camera.main).transform.parent).TryGetComponent<PlayerInventory>(ref pi))
						{
							<>8__1.__instance.pi = pi;
						}
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				if (((Behaviour)<>8__1.__instance).isActiveAndEnabled)
				{
					<>2__current = (object)new WaitForSeconds(30f);
					<>1__state = 5;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <RestartRecognizerCoroutine>d__6 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VoiceControlListener inst;

			private SpeechRecognizer <sr>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RestartRecognizerCoroutine>d__6(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<sr>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<sr>5__2 = GetOrBindSpeechRecognizer(inst);
					if ((Object)(object)<sr>5__2 == (Object)null)
					{
						MageArenaPortugueseMod.Log.LogError((object)"Sr is null");
						return false;
					}
					((SpeechProcessor)<sr>5__2).StopProcessing();
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					((SpeechProcessor)<sr>5__2).StartProcessing();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static string modelName = "vosk-model-small-pt-0.3";

		private static readonly MethodInfo tryresultMethod = AccessTools.Method(typeof(VoiceControlListener), "tryresult", new Type[1] { typeof(string) }, (Type[])null);

		private static readonly FieldInfo ResetMicCooldownField = AccessTools.Field(typeof(VoiceControlListener), "resetmiccooldown");

		private static readonly FieldInfo SrField = AccessTools.Field(typeof(VoiceControlListener), "sr");

		private static readonly Dictionary<string[], Action<VoiceControlListener>> portugueseCommandMap = new Dictionary<string[], Action<VoiceControlListener>>
		{
			{
				new string[2] { "fogo", "chamas" },
				delegate(VoiceControlListener v)
				{
					v.CastFireball();
				}
			},
			{
				new string[2] { "congelar", "gelo" },
				delegate(VoiceControlListener v)
				{
					v.CastFrostBolt();
				}
			},
			{
				new string[1] { "entrada" },
				delegate(VoiceControlListener v)
				{
					v.CastWorm();
				}
			},
			{
				new string[1] { "saída" },
				delegate(VoiceControlListener v)
				{
					v.CastHole();
				}
			},
			{
				new string[2] { "míssil mágico", "missil magico" },
				delegate(VoiceControlListener v)
				{
					v.CastMagicMissle();
				}
			},
			{
				new string[1] { "espelho meu" },
				delegate(VoiceControlListener v)
				{
					v.ActivateMirror();
				}
			}
		};

		private static readonly Dictionary<string, string[]> portugueseAdditionalCommandMap = new Dictionary<string, string[]>
		{
			{
				"blink",
				new string[4] { "clarão", "clarao", "teleporte", "piscar" }
			},
			{
				"wisp",
				new string[2] { "lento", "lentidão" }
			},
			{
				"divine",
				new string[2] { "luz divina", "luz" }
			},
			{
				"thunderbolt",
				new string[3] { "raio", "relâmpago", "relampago" }
			},
			{
				"blast",
				new string[4] { "explosão escura", "explosao escura", "explosão", "explosao" }
			},
			{
				"rock",
				new string[2] { "rocha", "pedra" }
			},
			{
				"echo location",
				new string[4] { "ecolocalização", "ecolocalizacao", "localização", "localizacao" }
			},
			{
				"magic shield",
				new string[3] { "escudo mágico", "escudo magico", "escudo" }
			},
			{
				"resurrection",
				new string[2] { "ressurreição", "ressurreicao" }
			},
			{
				"the eye of hell",
				new string[2] { "olho do inferno", "olho" }
			},
			{
				"hellfire",
				new string[1] { "chama infernal" }
			}
		};

		private static readonly MethodInfo restartsrMethod = AccessTools.Method(typeof(VoiceControlListener), "restartsr", (Type[])null, (Type[])null);

		private static readonly string[] SrFieldNames = new string[1] { "sr" };

		[HarmonyPatch("OnStartClient")]
		[HarmonyPostfix]
		private static void OnStartClient_Postfix(VoiceControlListener __instance)
		{
			((MonoBehaviour)__instance).StartCoroutine(CoWaitGetPlayer(__instance));
		}

		[IteratorStateMachine(typeof(<CoWaitGetPlayer>d__1))]
		private static IEnumerator CoWaitGetPlayer(VoiceControlListener __instance)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CoWaitGetPlayer>d__1(0)
			{
				__instance = __instance
			};
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPrefix]
		public static void LanguageModel_Ctor_Prefix(ref string path)
		{
			string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)MageArenaPortugueseMod.Instance).Info.Location), "LanguageModels", modelName);
			path = text;
			MageArenaPortugueseMod.Log.LogInfo((object)("Loading language model from: " + path));
		}

		[HarmonyPatch("tryresult")]
		[HarmonyPrefix]
		private static bool TryResultPrefix(VoiceControlListener __instance, string res)
		{
			if (string.IsNullOrWhiteSpace(res))
			{
				return false;
			}
			res = res.ToLowerInvariant().Trim();
			foreach (KeyValuePair<string[], Action<VoiceControlListener>> item in portugueseCommandMap)
			{
				if (item.Key.Any((string keyword) => res.Contains(keyword)))
				{
					item.Value(__instance);
				}
			}
			_ = __instance.SpellPages?.Count;
			foreach (ISpellCommand spellPage in __instance.SpellPages)
			{
				string spellName = spellPage.GetSpellName();
				foreach (KeyValuePair<string, string[]> item2 in portugueseAdditionalCommandMap)
				{
					bool flag = false;
					string[] value = item2.Value;
					foreach (string value2 in value)
					{
						if (res.Contains(value2))
						{
							flag = true;
							break;
						}
					}
					if (flag && string.Equals(spellName, item2.Key, StringComparison.OrdinalIgnoreCase))
					{
						spellPage.TryCastSpell();
					}
				}
				if (res.Contains(spellName.ToLowerInvariant()))
				{
					spellPage.TryCastSpell();
				}
			}
			return false;
		}

		[IteratorStateMachine(typeof(<RestartRecognizerCoroutine>d__6))]
		private static IEnumerator RestartRecognizerCoroutine(VoiceControlListener inst)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RestartRecognizerCoroutine>d__6(0)
			{
				inst = inst
			};
		}

		[HarmonyPatch("restartsr")]
		[HarmonyPrefix]
		private static bool RestartSrPrefix(VoiceControlListener __instance, ref IEnumerator __result)
		{
			__result = CoRestartSr(__instance);
			return false;
		}

		[IteratorStateMachine(typeof(<CoRestartSr>d__10))]
		private static IEnumerator CoRestartSr(VoiceControlListener inst)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CoRestartSr>d__10(0)
			{
				inst = inst
			};
		}

		[HarmonyPatch("resetmic")]
		[HarmonyPrefix]
		private static bool ResetMicPrefix(VoiceControlListener __instance)
		{
			if (ResetMicCooldownField != null)
			{
				float num = (float)(ResetMicCooldownField.GetValue(__instance) ?? ((object)0f));
				if (Time.time - num > 10f)
				{
					ResetMicCooldownField.SetValue(__instance, Time.time);
					((MonoBehaviour)__instance).StartCoroutine(CoResetMicLong(__instance));
				}
			}
			else
			{
				((MonoBehaviour)__instance).StartCoroutine(CoResetMicLong(__instance));
			}
			return false;
		}

		[HarmonyPatch("resetmiclong")]
		[HarmonyPrefix]
		private static bool ResetMicLongPrefix(VoiceControlListener __instance, ref IEnumerator __result)
		{
			__result = CoResetMicLong(__instance);
			return false;
		}

		[IteratorStateMachine(typeof(<CoResetMicLong>d__13))]
		private static IEnumerator CoResetMicLong(VoiceControlListener instance)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CoResetMicLong>d__13(0)
			{
				instance = instance
			};
		}

		private static void addSpellsToVocabulary(SpeechRecognizer recognizer)
		{
			foreach (KeyValuePair<string[], Action<VoiceControlListener>> item in portugueseCommandMap)
			{
				string[] key = item.Key;
				foreach (string text in key)
				{
					recognizer.Vocabulary.Add(text);
					MageArenaPortugueseMod.Log.LogInfo((object)("Adding " + text + " to vocabulary"));
				}
			}
			foreach (KeyValuePair<string, string[]> item2 in portugueseAdditionalCommandMap)
			{
				string[] key = item2.Value;
				foreach (string text2 in key)
				{
					recognizer.Vocabulary.Add(text2);
					MageArenaPortugueseMod.Log.LogInfo((object)("Adding " + text2 + " to vocabulary"));
				}
			}
		}

		private static SpeechRecognizer GetOrBindSpeechRecognizer(VoiceControlListener inst)
		{
			FieldInfo fieldInfo = null;
			FieldInfo fieldInfo2 = AccessTools.Field(((object)inst).GetType(), "sr");
			if (fieldInfo2 != null && typeof(SpeechRecognizer).IsAssignableFrom(fieldInfo2.FieldType))
			{
				object? value = fieldInfo2.GetValue(inst);
				SpeechRecognizer val = (SpeechRecognizer)((value is SpeechRecognizer) ? value : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				fieldInfo = fieldInfo2;
			}
			SpeechRecognizer val2 = ((Component)inst).GetComponent<SpeechRecognizer>() ?? ((Component)inst).GetComponentInChildren<SpeechRecognizer>(true);
			if ((Object)(object)val2 != (Object)null && fieldInfo != null)
			{
				fieldInfo.SetValue(inst, val2);
			}
			return val2;
		}

		private static VoiceBroadcastTrigger GetOrBindVbt(VoiceControlListener inst)
		{
			FieldInfo fieldInfo = null;
			FieldInfo fieldInfo2 = AccessTools.Field(((object)inst).GetType(), "vbt");
			if (fieldInfo2 != null && typeof(VoiceBroadcastTrigger).IsAssignableFrom(fieldInfo2.FieldType))
			{
				object? value = fieldInfo2.GetValue(inst);
				VoiceBroadcastTrigger val = (VoiceBroadcastTrigger)((value is VoiceBroadcastTrigger) ? value : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				fieldInfo = fieldInfo2;
			}
			VoiceBroadcastTrigger val2 = ((Component)inst).GetComponent<VoiceBroadcastTrigger>() ?? ((Component)inst).GetComponentInChildren<VoiceBroadcastTrigger>(true);
			if ((Object)(object)val2 != (Object)null && fieldInfo != null)
			{
				fieldInfo.SetValue(inst, val2);
			}
			return val2;
		}
	}
}
namespace MageArenaPortugueseVoiceMod
{
	[BepInPlugin("com.luisgbr1el.MageArenaPortugueseMod", "MageArenaPortugueseMod", "1.0.2")]
	public class MageArenaPortugueseMod : BaseUnityPlugin
	{
		private static Harmony Harmony;

		private ManualLogSource _log;

		internal static MageArenaPortugueseMod Instance { get; private set; }

		internal static ManualLogSource Log => Instance._log;

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Harmony = new Harmony("com.luisgbr1el.MageArenaPortugueseMod");
			Harmony.PatchAll();
			Log.LogWarning((object)"Portuguese Translation Loaded");
			Harmony.DEBUG = true;
		}
	}
}
namespace MageArenaPortuguese.Patches
{
	[HarmonyPatch]
	internal class InteractablePatch
	{
		[CompilerGenerated]
		private sealed class <TargetMethods>d__7 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private MethodBase <>2__current;

			private int <>l__initialThreadId;

			private IEnumerator<Type> <>7__wrap1;

			MethodBase IEnumerator<MethodBase>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TargetMethods>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = AccessTools.AllTypes().GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					while (<>7__wrap1.MoveNext())
					{
						Type current = <>7__wrap1.Current;
						if (!current.IsInterface && !current.IsAbstract && (typeof(IInteractable).IsAssignableFrom(current) || current.GetInterface("ITimedInteractable") != null))
						{
							MethodInfo methodInfo = AccessTools.Method(current, "DisplayInteractUI", (Type[])null, (Type[])null);
							if (methodInfo != null)
							{
								<>2__current = methodInfo;
								<>1__state = 1;
								return true;
							}
						}
					}
					<>m__Finally1();
					<>7__wrap1 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap1 != null)
				{
					<>7__wrap1.Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TargetMethods>d__7(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<MethodBase>)this).GetEnumerator();
			}
		}

		private const string _graspPrefix = "Grasp ";

		private const string _makePrefix = "Make ";

		private const string _placePrefix = "Place ";

		private const string _openPrefix = "Open ";

		private const string _openePrefix = "Opene ";

		private const string _shutPrefix = "Shut ";

		private static readonly HashSet<string> loggedTexts = new HashSet<string>();

		[IteratorStateMachine(typeof(<TargetMethods>d__7))]
		private static IEnumerable<MethodBase> TargetMethods()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TargetMethods>d__7(-2);
		}

		private static void Postfix(ref string __result)
		{
			if (!string.IsNullOrWhiteSpace(__result))
			{
				TranslationManager.InteractionType? interactionType = null;
				if (__result.StartsWith("Grasp ", StringComparison.OrdinalIgnoreCase))
				{
					interactionType = TranslationManager.InteractionType.Pegar;
					__result = __result.Substring("Grasp ".Length).Trim();
				}
				else if (__result.StartsWith("Make ", StringComparison.OrdinalIgnoreCase))
				{
					interactionType = TranslationManager.InteractionType.Fazer;
					__result = __result.Substring("Make ".Length).Trim();
				}
				else if (__result.StartsWith("Place ", StringComparison.OrdinalIgnoreCase))
				{
					interactionType = TranslationManager.InteractionType.Colocar;
					__result = __result.Substring("Place ".Length).Trim();
				}
				else if (__result.StartsWith("Open ", StringComparison.OrdinalIgnoreCase) || __result.StartsWith("Opene ", StringComparison.OrdinalIgnoreCase))
				{
					interactionType = TranslationManager.InteractionType.Abrir;
					__result = __result.Substring("Open ".Length).Trim();
				}
				else if (__result.StartsWith("Shut ", StringComparison.OrdinalIgnoreCase))
				{
					interactionType = TranslationManager.InteractionType.Fechar;
					__result = __result.Substring("Shut ".Length).Trim();
				}
				string text = TranslationManager.Get("interactable", __result, interactionType);
				if (text != __result)
				{
					__result = text;
				}
				else
				{
					__result.Trim();
				}
			}
		}
	}
	[HarmonyPatch(typeof(MainMenuManager), "Start")]
	internal class MainMenuManagerPatch
	{
		private static void Postfix()
		{
			TranslateUI();
		}

		private static void TranslateUI()
		{
			Text[] array = Object.FindObjectsByType<Text>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (Text val in array)
			{
				string text = val.text;
				string text2 = TranslationManager.Get("menu", text);
				if (text2 != text)
				{
					val.text = text2;
				}
			}
			TMP_Text[] array2 = Object.FindObjectsByType<TMP_Text>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (TMP_Text val2 in array2)
			{
				string text3 = val2.text;
				string text4 = TranslationManager.Get("menu", text3);
				if (text4 != text3)
				{
					val2.text = text4;
				}
			}
		}

		[HarmonyPatch("ChangeTeamText")]
		[HarmonyPrefix]
		private static void ChangeTeamText_Prefix(ref string lvlandrank)
		{
			if (!string.IsNullOrEmpty(lvlandrank))
			{
				lvlandrank = lvlandrank.Replace("_", " ");
			}
		}

		[HarmonyPatch("ChangeTeamText")]
		[HarmonyPostfix]
		private static void ChangeTeamText_Postfix(int team, int index, string lvlandrank, MainMenuManager __instance)
		{
			if (string.IsNullOrEmpty(lvlandrank))
			{
				return;
			}
			string[] array = lvlandrank.Split(new char[1] { ' ' });
			if (array.Length >= 2)
			{
				string text = TranslationManager.Get("rankings", array[2]);
				string text2 = "Nível " + array[1] + " (" + text + ")";
				if (team == 0)
				{
					__instance.team1rankandleveltext[index].text = text2;
				}
				else
				{
					__instance.team2rankandleveltext[index].text = text2;
				}
			}
		}

		[HarmonyPatch("SyncUpdateNames")]
		[HarmonyPrefix]
		private static void SyncUpdateNames_Prefix(ref string[] PlayerNames, ref string[] PlayerRanks)
		{
			for (int i = 0; i < PlayerNames.Length; i++)
			{
				if (PlayerNames[i] != null && PlayerRanks[i] != null)
				{
					PlayerRanks[i] = PlayerRanks[i].Replace("_", " ");
				}
			}
		}

		[HarmonyPatch("SyncUpdateNames")]
		[HarmonyPostfix]
		private static void SyncUpdateNames_Postfix(ref string[] PlayerNames, ref string[] PlayerRanks, MainMenuManager __instance)
		{
			for (int i = 0; i < PlayerNames.Length; i++)
			{
				if (PlayerNames[i] != null && !string.IsNullOrEmpty(PlayerRanks[i]))
				{
					string[] array = PlayerRanks[i].Split(new char[1] { ' ' });
					if (array.Length >= 2)
					{
						string text = TranslationManager.Get("rankings", array[2]);
						string text2 = "Nível " + array[1] + " (" + text + ")";
						__instance.rankandleveltext[i].text = text2;
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(TMP_Text))]
	internal class TMPTextTipsPatch
	{
		private static MethodBase TargetMethod()
		{
			return typeof(TMP_Text).GetProperty("text").GetSetMethod(nonPublic: true);
		}

		private static void Prefix(TMP_Text __instance, ref string value)
		{
			if (!string.IsNullOrWhiteSpace(value))
			{
				string text = TranslationManager.Get("tips", value);
				if (text != value)
				{
					value = text;
				}
			}
		}
	}
}
namespace MageArenaPortuguese.Config
{
	public static class TranslationManager
	{
		public enum InteractionType
		{
			Pegar,
			Colocar,
			Fazer,
			Abrir,
			Fechar
		}

		private static readonly Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>();

		private static bool isLoaded = false;

		private static readonly Dictionary<string, string> tips = new Dictionary<string, string>
		{
			{ "Scroll to equip your torch", "Gire a roda do mouse para equipar sua tocha" },
			{ "Hold LMB to light the brazier", "Segure o botão esquerdo para acender o braseiro" },
			{ "[Press RMB to Continue]", "[Pressione o botão direito do mouse para continuar]" },
			{ "There are flag poles in each team's base and throughout the map. Hold Q to view the map. [Press RMB to Continue]", "Há bandeiras em cada base do time e espalhadas pelo mapa. Segure Q para ver o mapa. [Pressione o botão direito do mouse para continuar]" },
			{ "If the flag pole in your base is captured, you will not be resurrected when you die. Recall to your base by pressing B. [Press RMB to Continue]", "Se a bandeira da sua base for capturada, você não será ressuscitado quando morrer. [Pressione o botão direito do mouse para continuar]" },
			{ "The orb in the bottom of your screen indicates if you will resurrect upon death. A red skull in the orb means you will die forever. [Press RMB to Continue]", "O orbe na parte inferior da tela indica se você vai reviver ao morrer. Uma caveira vermelha no orbe significa que você morrerá para sempre. [Pressione o botão direito do mouse para continuar]" },
			{ "To achieve Victory, control the flag pole in your opponents base and eliminate each of your opponents. [Press RMB to Continue]", "Para conseguir a vitória, domine a bandeira da base dos seus oponentes e elimine-os. [Pressione o botão direito do mouse para continuar]" },
			{ "Controlling flagpoles around the map grants you resources and XP. [Press RMB to Continue]", "Dominar as bandeiras pelo mapa dá a você recursos e XP. [Pressione o botão direito do mouse para continuar]" },
			{ "Stand Next to the flag pole to capture it.", "Fique ao lado da bandeira para capturá-la." },
			{ "Press E to pickup the Frog and Log and place them on the crafting table to craft a Frog Spear.", "Pressione E para pegar o Sapo e o Tronco, e coloque-os na mesa de criação para criar uma Vareta de Sapo." },
			{ "Equip your spellbook, press 1 to turn to the page Fireball. Then say the word \"Fireball\" to cast Fireball", "Equipe seu Livro de Feitiços e pressione 1 para abrir a página da Bola de Fogo. Então, diga \"fogo\" ou \"chamas\" para lançá-la." },
			{ "Press 2 to turn to the page Frost Bolt. Then say the word \"Freeze\" to cast Frost Bolt", "Pressione 2 para abrir a página do Raio de Gelo. Então diga \"gelo\" ou \"congelar\" para lançá-lo." },
			{ "Press 3 to turn to the page Worm Hole. Then say the word \"Worm\" to cast the first half of Worm Hole", "Pressione 3 para abrir a página do Buraco de Minhoca. Então diga \"entrada\" para lançar a primeira parte do Buraco de Minhoca." },
			{ "Now move to a new location and say the word \"Hole\" to cast the second half of Worm Hole", "Agora vá até um novo local e diga \"saída\" para lançar a segunda parte do Buraco de Minhoca." },
			{ "Press 4 to turn to the page Magic Missle. Then say the words \"Magic Missle\" to cast Magic Missle", "Pressione 4 para abrir a página do Míssil Mágico. Então diga \"míssil mágico\" para lançá-lo." },
			{ "You have passed the Academy of Sorceries final examination. You may now exit the tutorial.", "Você passou no exame final da Academia de Feitiçaria. Agora pode sair do tutorial." },
			{ "A strong magical presence dispells your worm...", "Uma forte presença mágica dissipa a entrada do seu Buraco de Minhoca..." },
			{ "A strong magical presence dispells your hole...", "Uma forte presença mágica dissipa a saída do seu Buraco de Minhoca..." },
			{ "A surge of magical energy passes through you...", "Uma onda de energia mágica passa por você..." },
			{ "Your spells grow stronger...", "Seus feitiços ficam mais fortes..." },
			{ "Your voice bellows from the mountain tops...", "Sua voz ecoa dos topos das montanhas..." },
			{ "Your joints feel like rubber...", "Suas articulações parecem borracha..." },
			{ "Your tounge gains a mind of its own...", "Sua língua ganha vida própria..." },
			{ "Your skin hardens like tree bark...", "Sua pele endurece como casca de árvore..." }
		};

		private static readonly Dictionary<string, string> menu = new Dictionary<string, string>
		{
			{ "Play Tutorial", "Jogar Tutorial" },
			{ "Create Lobby", "Criar Lobby" },
			{ "Join Lobby", "Entrar no Lobby" },
			{ "Credits", "Créditos" },
			{ "Quit Game", "Sair do Jogo" },
			{ "ATTENTION!", "ATENÇÃO!" },
			{ "People with non-American accents please click here", "Sotaque não-americano?\nClique aqui." },
			{ "Accent Menu", "Menu de Sotaques" },
			{ "Voice Detection tips:\n\nSay spell names once, do not say them over and over.\n\nYour microphone peaking too long will cause voice recognition to fail.\n\nPlace your mic further away from you if you want to scream spells, and do not scream directly into it.\n\nThe game has to use your windows default microphone, this can be changed in windows sound settings", "Tradução em Português por @luisgbr1el\n\nDicas de detecção de voz:\n\nDiga o nome dos feitiços apenas uma vez, não os repita várias vezes.\n\nSe o seu microfone ficar saturado por muito tempo, o reconhecimento de voz pode falhar.\n\nColoque o microfone mais distante de você se quiser gritar os feitiços e não grite diretamente nele.\n\nO jogo precisa usar o microfone padrão do Windows, isso pode ser alterado nas configurações de som do Windows." },
			{ "Edit Team Flag", "Editar bandeira" },
			{ "Kick", "Remover" },
			{ "Are you sure?", "Tem certeza?" },
			{ "Generating World...", "Gerando mundo..." },
			{ "Reset", "Resetar" },
			{ "Player 1", "Jogador 1" },
			{ "Back", "Voltar" },
			{ "Capture the flag", "Capture a bandeira" },
			{ "Capture the Flag", "Capture a bandeira" },
			{ "British", "Britânico" },
			{ "Traits", "Características" },
			{ "Reset Voice Detection", "Resetar detecção de voz" },
			{ "Fullscreen", "Tela cheia" },
			{ "The Host Leaving will disband the lobby", "Se o host sair, o lobby será desfeito" },
			{ "Play Again", "Jogar novamente" },
			{ "American", "Americano" },
			{ "Deathmatch", "Mata-mata" },
			{ "MB3", "Rol." },
			{ "Start Game", "Iniciar jogo" },
			{ "!Public lobbies are expierencing a large number of game breaking bugs!", "Os lobbies públicos estão com um grande número de bugs críticos!" },
			{ "LMB", "Botão esq." },
			{ "Send", "Enviar" },
			{ "Players will not be able to join past this point.", "Os jogadores não poderão entrar a partir deste ponto." },
			{ "Kick Player Menu", "Menu de expulsão de jogador" },
			{ "Make Private", "Privado" },
			{ "Make Public", "Público" },
			{ "Error version mismatch! Restart Steam to update.", "Erro de incompatibilidade de versão! Reinicie o Steam para atualizar." },
			{ "Leave Game", "Sair do jogo" },
			{ "(Click if you cant cast spells)", "(Se não conseguir lançar feitiços)" },
			{ "Indian", "Indiano" },
			{ "Settings", "Configurações" },
			{ "Save to Disk", "Salvar no disco" },
			{ "Colosseum", "Coliseu" },
			{ "Spacebar", "Barra de espaço" },
			{ "Large", "Grande" },
			{ "Leave Lobby", "Sair do Lobby" },
			{ "Join Sorcerers", "Juntar-se aos Feitiçeiros" },
			{ "Join Warlocks", "Juntar-se aos Bruxos" },
			{ "Copy LobbyID to\nClipboard", "Copiar ID" },
			{ "Start Lobby", "Iniciar Lobby" },
			{ "Soups Drank", "Sopas tomadas" },
			{ "Kills", "Abates" },
			{ "Medium", "Médio" },
			{ "Windowed", "Modo janela" },
			{ "Borderless", "Sem bordas" },
			{ "Find a public match", "Procurar uma partida pública" },
			{ "Enter Lobby", "Entrar no Lobby" },
			{ "Leave", "Sair" },
			{ "Distance Traveled", "Distância percorrida" },
			{ "Join private by Lobby ID:", "Entrar por ID:" },
			{ "Version 0.7.6", "Versão 0.7.6" },
			{ "Deaths", "Mortes" },
			{ "Spells Cast", "Feitiços lançados" },
			{ "Load from disk", "Carregar do disco" },
			{ "Refresh", "Atualizar" },
			{ "Filter by", "Filtrar por" },
			{ "Your spells gain power...", "Seus feitiços ganham poder..." },
			{ "Click to Reveal Lobby ID", "Clique para ver o ID do Lobby" },
			{ "Enter text...", "Digite aqui..." },
			{ "The only available language currently is English.\nMultiple Languages will be available in a later update.\n\nUnfortunately, accents can cause the voice detection to not work as well.\n\nIf you do not have one of the following accents, try out all three.\n\n\n\n\n\n\nThese three are the only English accent options available.", "O único idioma disponível nativamente atualmente é o inglês.\n(Tradução em Português por luisgbr1el)\nMais idiomas estarão disponíveis em uma atualização futura.\n\nInfelizmente, sotaques podem fazer com que a detecção de voz não funcione bem.\n\nSe você não tiver um dos sotaques abaixo, experimente os três.\n\n\n\n\n\n\nEssas são as únicas opções de sotaque em inglês disponíveis." },
			{ "This will overwrite\nthe current drawing!", "Isso irá sobrescrever\no desenho atual!" },
			{ "Drop", "Soltar" },
			{ "Flip Page", "Virar página" },
			{ "Licensed textures obtained from freepbr.com", "Texturas licenciadas obtidas de freepbr.com" },
			{ "Movement Keys", "Teclas de movimento" },
			{ "Error Lobby ID did not generate. Sorry. Try relaunching the game.", "Erro: O ID do Lobby não foi gerado. Tente reiniciar o jogo." },
			{ "Map Size:", "Tamanho do mapa:" },
			{ "title", "title [teste]" },
			{ "Microphone is the Windows Default Mic this can not be changed. Check in Windows sound settings.", "O microfone é o padrão do Windows. Abra as configurações de som do Windows para alterar." },
			{ "Restore Defaults", "Redefinir padrões" },
			{ "Lobby ID: (send this to your friends)", "ID do Lobby: (mande para seus amigos)" },
			{ "Push to talk has been temporarily disabled", "O aperte para falar está desativado" },
			{ "Mouse Sensitivity", "Sensibilidade do mouse" },
			{ "Jump", "Pular" },
			{ "Interact", "Interagir" },
			{ "Crouch", "Agachar" },
			{ "Sprint", "Correr" },
			{ "Save", "Salvar" },
			{ "Map", "Mapa" },
			{ "Contact me on twitter/x: @jrsjams_", "Contate-me no Twitter/X: @jrsjams_\nTradução em Português por @luisgbr1el" },
			{ "Many Sound effects obtained from ZapSplat at zapsplat.com", "Muitos efeitos sonoros obtidos de ZapSplat em zapsplat.com" },
			{ "This will overwrite\nyour previously saved flag!", "Isso irá sobrescrever sua\n bandeira salva anteriormente!" },
			{ "Limit Fps", "Limitar FPS" },
			{ "Use Item", "Usar item" },
			{ "Screen Mode:", "Modo de tela:" },
			{ "Quick Swap Item Keys", "Teclas de troca rápida" },
			{ "British has been disabled,\nIt did not work for anyone", "O britânico foi desativado,\nnão está funcionando." },
			{ "Deathmatch 1v1", "Mata-mata 1v1" },
			{ "Recall", "Voltar\np/ base" },
			{ "Option A", "Opção A" },
			{ "Select Brush Size:", "Tamanho do pincel:" }
		};

		private static readonly Dictionary<string, string> interactable = new Dictionary<string, string>
		{
			{ "Move to Close", "Mova-se para fechar" },
			{ "Read Crafting Manual", "Ler manual de criação" },
			{ "Speak to Soup Man", "Falar com o Homem-Sopa" },
			{ "SpeaK to Knight", "Falar com o Cavaleiro" },
			{ "Enter Mausoleum", "Entrar no Mausoléu" },
			{ "Exit Mausoleum", "Sair do Mausoléu" },
			{ "Mirror mirror...", "Espelho, espelho meu..." },
			{ "Trade Item", "Trocar Item" },
			{ "Item", "Item" },
			{ "Dore", "Porta" },
			{ "Chest", "Baú" },
			{ "the Portcullis", "a grade" },
			{ "Torn Page", "Folha Rasgada" },
			{ "Bounce Mush", "Cogumelo Saltitante" },
			{ "Crystal", "Cristal" },
			{ "Pull Hilt of Excalibur", "Puxar Cabo da Excalibur" },
			{ "Log", "Tronco" },
			{ "RocK", "Pedra" },
			{ "Pull Shattered Blade of Excalibur", "Puxar Lâmina Estilhaçada da Excalibur" },
			{ "Toad", "Sapo" },
			{ "Crystal Soup", "Sopa de Cristal" },
			{ "Frog Soup", "Sopa de Sapo" },
			{ "Log Soup", "Sopa de Tronco" },
			{ "Mushroom Soup", "Sopa de Cogumelo" },
			{ "Rock Soup", "Sopa de Pedra" },
			{ "Boinger", "Saltador" },
			{ "Dart Gun", "Sapo-Dardo" },
			{ "Excalibur", "Excalibur" },
			{ "Frog Balloon", "Balão de Sapo" },
			{ "Frog Spear", "Vareta de Sapo" },
			{ "Frogleather Blade", "Espada de Couro de Sapo" },
			{ "Fungal Walking Stick", "Bengala Fúngica" },
			{ "Golum", "Golem" },
			{ "Levitator", "Levitador" },
			{ "Mushroom Man", "Homem-Cogumelo" },
			{ "Mushroom Swerd", "Espada-Cogumelo" },
			{ "Ray of Shrink", "Raio Encolhedor" },
			{ "Silverseed Bramble", "Semente-de-Prata Espinhosa" },
			{ "Spore Frog", "Sapo de Esporos" },
			{ "The Orb", "Orbe" },
			{ "Thrumming Stone", "Pedra Vibrante" },
			{ "Walking Stick", "Bengala" },
			{ "BooK", "Livro de Feitiços" },
			{ "Torch", "Tocha" },
			{ "Weed of the Pipe", "Erva do Cachimbo" }
		};

		private static readonly Dictionary<string, string> rankings = new Dictionary<string, string>
		{
			{ "Lackey", "Lacaio" },
			{ "Sputterer", "Gaguejador" },
			{ "Novice", "Novato" },
			{ "Apprentice", "Aprendiz" },
			{ "Savant", "Erudito" },
			{ "Master", "Mestre" },
			{ "Grand", "Grão-Mestre" },
			{ "Supreme", "Supremo" },
			{ "Archmagus", "Arqui-Mago" },
			{ "Prime", "Primordial" }
		};

		private static void LoadTranslations()
		{
			translations["tips"] = tips;
			translations["menu"] = menu;
			translations["interactable"] = interactable;
			translations["rankings"] = rankings;
			isLoaded = true;
		}

		public static string Get(string category, string key, InteractionType? interactionType = null)
		{
			if (!isLoaded)
			{
				LoadTranslations();
			}
			string key2 = key.Trim();
			if (translations.ContainsKey(category) && translations[category].ContainsKey(key2))
			{
				string text = translations[category][key2];
				if (interactionType.HasValue)
				{
					return $"{interactionType} {text}";
				}
				return text;
			}
			return key;
		}
	}
}