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 Galdr v0.8.6
plugins/Galdr/Galdr.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace Galdr; public static class ConfigSync { private static readonly List<ConfigEntryBase> Entries = new List<ConfigEntryBase>(); private static readonly Dictionary<string, string> Overrides = new Dictionary<string, string>(); private static readonly Dictionary<string, float> FloatCache = new Dictionary<string, float>(); public static bool HasServerValues => Overrides.Count > 0; private static string Key(ConfigEntryBase e) { return e.Definition.Section + "/" + e.Definition.Key; } public static void Register(ConfigEntryBase e) { Entries.Add(e); } public static bool TryGetFloat(ConfigEntryBase e, out float v) { v = 0f; if (Overrides.Count == 0) { return false; } string key = Key(e); if (FloatCache.TryGetValue(key, out v)) { return true; } if (!Overrides.TryGetValue(key, out var value)) { return false; } if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) { return false; } FloatCache[key] = v; return true; } public static bool TryGetString(ConfigEntryBase e, out string v) { v = null; if (Overrides.Count > 0) { return Overrides.TryGetValue(Key(e), out v); } return false; } public static void Reset() { Overrides.Clear(); FloatCache.Clear(); } public static void RequestFromServer() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown if (!((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null && !ZNet.instance.IsServer()) { ZPackage val = new ZPackage(); val.Write("0.8.6"); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Galdr_CfgReq", new object[1] { val }); } } public static void OnRequest(long sender, ZPackage req) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } string text = "?"; try { text = req.ReadString(); } catch { } if (text != "0.8.6") { Plugin.Log.LogWarning((object)("A player joined with Galdr " + text + ", the server runs 0.8.6")); } ZPackage val = new ZPackage(); val.Write(Entries.Count); foreach (ConfigEntryBase entry in Entries) { val.Write(Key(entry)); val.Write(entry.GetSerializedValue()); } val.Write("0.8.6"); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Galdr_Cfg", new object[1] { val }); } public static void OnConfig(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } Reset(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { string key = pkg.ReadString(); string value = pkg.ReadString(); Overrides[key] = value; } Plugin.Log.LogInfo((object)("Balance received from the server: " + num + " values")); string text = "?"; try { text = pkg.ReadString(); } catch { } if (text != "0.8.6") { Plugin.Log.LogWarning((object)("Galdr version differs: server " + text + ", you 0.8.6")); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, Lang.F("sync.version_mismatch", text, "0.8.6"), 0, (Sprite)null, false); } } } } public class SyncedFloat { public readonly ConfigEntry<float> Entry; public float Value { get { if (!ConfigSync.TryGetFloat((ConfigEntryBase)(object)Entry, out var v)) { return Entry.Value; } return v; } } public SyncedFloat(ConfigEntry<float> entry) { Entry = entry; ConfigSync.Register((ConfigEntryBase)(object)entry); } } public class SyncedString { public readonly ConfigEntry<string> Entry; public string Value { get { if (!ConfigSync.TryGetString((ConfigEntryBase)(object)Entry, out var v)) { return Entry.Value; } return v; } } public SyncedString(ConfigEntry<string> entry) { Entry = entry; ConfigSync.Register((ConfigEntryBase)(object)entry); } } public static class GaldrConfig { public static ConfigEntry<KeyCode> CastKey; public static ConfigEntry<KeyCode> TreeKey; public static ConfigEntry<string> ModelPath; public static ConfigEntry<string> VoiceLanguage; public static ConfigEntry<string> ExtraStopWords; public static ConfigEntry<string> MicDevice; public static ConfigEntry<float> MatchThreshold; public static ConfigEntry<float> InstantThreshold; public static ConfigEntry<float> NoiseGate; public static ConfigEntry<float> BindConsistency; public static ConfigEntry<float> BindConflict; public static ConfigEntry<bool> ShowHeard; public static ConfigEntry<bool> HideWords; public static ConfigEntry<bool> SpellBar; public static SyncedFloat LoadoutSlots; public static ConfigEntry<string> HandAnim; public static ConfigEntry<bool> QuickCast; public static ConfigEntry<bool> Loudness; public static ConfigEntry<bool> ReadyChime; public static ConfigEntry<bool> CrosshairWord; public static ConfigEntry<bool> HandGlow; public static ConfigEntry<bool> LearnWords; public static ConfigEntry<bool> SuggestWords; public static ConfigEntry<string> ListenMode; public static ConfigEntry<KeyCode> ConfirmKey; public static SyncedFloat ShoutBonus; public static SyncedFloat RestedRegen; public static SyncedFloat AltarRegen; public static SyncedFloat RuneFoes; public static ConfigEntry<bool> RequireStaff; public static ConfigEntry<float> UiScale; public static ConfigEntry<float> HudX; public static ConfigEntry<float> HudY; public static ConfigEntry<bool> DebugCheat; public static ConfigEntry<bool> TestCast; public static ConfigEntry<bool> BookEnabled; public static ConfigEntry<float> BookCheckSeconds; public static ConfigEntry<float> BookLeaseHours; public static ConfigEntry<float> BookExtra; public static SyncedFloat NotesChance; public static SyncedFloat TrickChance; public static SyncedFloat TrophyFirstMult; public static SyncedFloat TrophyRepeatMult; public static ConfigEntry<KeyCode> TestCastKey; public static readonly Dictionary<int, SyncedFloat> KillByBiome = new Dictionary<int, SyncedFloat>(); public static SyncedFloat Star1Mult; public static SyncedFloat Star2Mult; public static SyncedFloat HealPerKnowledge; public static SyncedFloat RuneStoneReward; public static SyncedFloat SummonShare; public static SyncedFloat CastPerTier; public static SyncedFloat[] BossFirst = new SyncedFloat[7]; public static SyncedFloat[] BossRepeat = new SyncedFloat[7]; public static SyncedFloat[] RankBase = new SyncedFloat[7]; public static SyncedFloat[] OpenPrice = new SyncedFloat[7]; public static SyncedFloat ForeignMult; public static SyncedFloat Threshold; public static SyncedFloat CoreRankBase; public static SyncedString[] BossGate = new SyncedString[7]; public static SyncedFloat PowerPerRank; public static SyncedFloat ManaPerRank; public static SyncedFloat CooldownPerRank; public static SyncedFloat ManaBase; public static SyncedFloat ManaRegen; public static SyncedFloat CoreManaPerRank; public static SyncedFloat CoreRegenPerRank; public static SyncedFloat CoreMightPerRank; public static SyncedFloat MagicArmor; public static SyncedFloat PvpControl; public static SyncedFloat UseEitr; public static SyncedFloat Resonance; public static SyncedFloat BossPercentMult; public static SyncedFloat AllowPvp; public static SyncedFloat UseWeakness; public static SyncedFloat SkillBonus; public static SyncedFloat ProjectileSpeed; public static SyncedFloat Misfires; public static SyncedString RespecItem; public static SyncedFloat RespecAmount; public static SyncedFloat RemoveVanillaMagic; public const int Meadows = 1; public const int Swamp = 2; public const int Mountain = 4; public const int BlackForest = 8; public const int Plains = 16; public const int AshLands = 32; public const int DeepNorth = 64; public const int Ocean = 256; public const int Mistlands = 512; public static readonly string[] BossTokens = new string[7] { "$enemy_eikthyr", "$enemy_gdking", "$enemy_bonemass", "$enemy_dragon", "$enemy_goblinking", "$enemy_seekerqueen", "$enemy_fader" }; public static readonly string[] BossKeys = new string[7] { "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" }; private static ConfigFile _cfg; private static readonly Dictionary<string, float> OldDefaults = new Dictionary<string, float> { { "3_1/Power", 15f }, { "3_1/Cooldown", 4f }, { "3_2/Power", 12f }, { "3_2/ManaCost", 25f }, { "3_2/Cooldown", 10f }, { "3_5/Power", 4f } }; public static string BossTitle(int i) { return Progression.BossName(BossKeys[i]); } private static SyncedFloat F(string section, string key, float def, string desc) { return new SyncedFloat(_cfg.Bind<float>(section, key, def, desc)); } private static string D(string key, params object[] args) { return Lang.F("cfg." + key, args); } public static void Init(ConfigFile cfg) { _cfg = cfg; CastKey = cfg.Bind<KeyCode>("1. Controls", "CastKey", (KeyCode)326, D("CastKey")); TreeKey = cfg.Bind<KeyCode>("1. Controls", "GaldrWindowKey", (KeyCode)107, D("GaldrWindowKey")); RequireStaff = cfg.Bind<bool>("1. Controls", "RequireStaff", false, D("RequireStaff")); UiScale = cfg.Bind<float>("1. Controls", "UiScale", 1f, D("UiScale")); HudX = cfg.Bind<float>("1. Controls", "HudX", 30f, D("HudX")); HudY = cfg.Bind<float>("1. Controls", "HudY", 175f, D("HudY")); SpellBar = cfg.Bind<bool>("1. Controls", "WordBar", true, D("WordBar")); LoadoutSlots = F("1. Controls", "LoadoutSlots", 4f, D("LoadoutSlots")); HandAnim = cfg.Bind<string>("1. Controls", "CastAnimationWithoutStaff", "throw_bomb", D("CastAnimationWithoutStaff")); QuickCast = cfg.Bind<bool>("1. Controls", "QuickCast", true, D("QuickCast")); ReadyChime = cfg.Bind<bool>("1. Controls", "ReadyChime", true, D("ReadyChime")); CrosshairWord = cfg.Bind<bool>("1. Controls", "WordAtCrosshair", true, D("WordAtCrosshair")); HandGlow = cfg.Bind<bool>("1. Controls", "ListeningGlow", true, D("ListeningGlow")); ListenMode = cfg.Bind<string>("1. Controls", "ListenMode", "Hold", D("ListenMode")); ConfirmKey = cfg.Bind<KeyCode>("1. Controls", "ConfirmWordKey", (KeyCode)121, D("ConfirmWordKey")); ModelPath = cfg.Bind<string>("2. Voice", "ModelPath", "", D("ModelPath")); VoiceLanguage = cfg.Bind<string>("2. Voice", "VoiceLanguage", "auto", D("VoiceLanguage")); MicDevice = cfg.Bind<string>("2. Voice", "Microphone", "", D("Microphone")); MatchThreshold = cfg.Bind<float>("2. Voice", "MatchThreshold", 0.72f, D("MatchThreshold")); InstantThreshold = cfg.Bind<float>("2. Voice", "InstantThreshold", 0.9f, D("InstantThreshold")); NoiseGate = cfg.Bind<float>("2. Voice", "NoiseGate", 0f, D("NoiseGate")); Loudness = cfg.Bind<bool>("2. Voice", "WhisperAndShout", true, D("WhisperAndShout")); LearnWords = cfg.Bind<bool>("2. Voice", "LearnWords", true, D("LearnWords")); SuggestWords = cfg.Bind<bool>("2. Voice", "SuggestWords", true, D("SuggestWords")); BindConsistency = cfg.Bind<float>("2. Voice", "BindConsistency", 0.6f, D("BindConsistency")); BindConflict = cfg.Bind<float>("2. Voice", "BindConflict", 0.75f, D("BindConflict")); ExtraStopWords = cfg.Bind<string>("2. Voice", "ExtraStopWords", "", D("ExtraStopWords")); ShowHeard = cfg.Bind<bool>("2. Voice", "ShowHeard", true, D("ShowHeard")); HideWords = cfg.Bind<bool>("2. Voice", "HideWords", false, D("HideWords")); Misfires = new SyncedFloat(cfg.Bind<float>("5. Effects", "Misfires", 1f, D("Misfires"))); DebugCheat = cfg.Bind<bool>("9. Debug", "KnowledgeButton", false, D("KnowledgeButton")); TestCast = cfg.Bind<bool>("9. Debug", "CastWithoutVoice", false, D("CastWithoutVoice")); TestCastKey = cfg.Bind<KeyCode>("9. Debug", "TestCastKey", (KeyCode)327, D("TestCastKey")); BookEnabled = cfg.Bind<bool>("7. Galdrabok", "Enabled", true, D("Enabled")); BookCheckSeconds = cfg.Bind<float>("7. Galdrabok", "CheckSeconds", 180f, D("CheckSeconds")); BookLeaseHours = cfg.Bind<float>("7. Galdrabok", "LostAfterHours", 168f, D("LostAfterHours")); BookExtra = cfg.Bind<float>("7. Galdrabok", "ExtraBooks", 0f, D("ExtraBooks")); NotesChance = new SyncedFloat(cfg.Bind<float>("7. Galdrabok", "NotesChance", 0.12f, D("NotesChance"))); TrickChance = new SyncedFloat(cfg.Bind<float>("7. Galdrabok", "TechniqueChance", 0.05f, D("TechniqueChance"))); TrophyFirstMult = new SyncedFloat(cfg.Bind<float>("7. Galdrabok", "FirstTrophy", 10f, D("FirstTrophy"))); TrophyRepeatMult = new SyncedFloat(cfg.Bind<float>("7. Galdrabok", "RepeatTrophy", 1f, D("RepeatTrophy"))); RuneFoes = F("8. Foes", "RuneFoes", 1f, D("RuneFoes")); KillByBiome[1] = F("3. Knowledge", "KillMeadows", 2f, D("kill", D("biome.Meadows"))); KillByBiome[8] = F("3. Knowledge", "KillBlackForest", 4f, D("kill", D("biome.BlackForest"))); KillByBiome[2] = F("3. Knowledge", "KillSwamp", 7f, D("kill", D("biome.Swamp"))); KillByBiome[4] = F("3. Knowledge", "KillMountain", 10f, D("kill", D("biome.Mountain"))); KillByBiome[16] = F("3. Knowledge", "KillPlains", 14f, D("kill", D("biome.Plains"))); KillByBiome[512] = F("3. Knowledge", "KillMistlands", 18f, D("kill", D("biome.Mistlands"))); KillByBiome[32] = F("3. Knowledge", "KillAshlands", 24f, D("kill", D("biome.Ashlands"))); KillByBiome[64] = F("3. Knowledge", "KillDeepNorth", 24f, D("kill", D("biome.DeepNorth"))); KillByBiome[256] = F("3. Knowledge", "KillOcean", 10f, D("kill", D("biome.Ocean"))); Star1Mult = F("3. Knowledge", "Star1Mult", 2f, D("Star1Mult")); Star2Mult = F("3. Knowledge", "Star2Mult", 3f, D("Star2Mult")); HealPerKnowledge = F("3. Knowledge", "HealPerKnowledge", 0f, D("HealPerKnowledge")); RuneStoneReward = F("3. Knowledge", "RuneStone", 10f, D("RuneStone")); SummonShare = F("3. Knowledge", "SummonShare", 0.5f, D("SummonShare")); CastPerTier = F("3. Knowledge", "PerCast", 1f, D("PerCast")); float[] array = new float[7] { 80f, 150f, 250f, 400f, 600f, 800f, 1000f }; float[] array2 = new float[7] { 20f, 40f, 60f, 100f, 150f, 200f, 250f }; for (int i = 0; i < 7; i++) { BossFirst[i] = F("3. Knowledge", "Boss" + (i + 1) + "First", array[i], D("boss_first", BossTitle(i))); BossRepeat[i] = F("3. Knowledge", "Boss" + (i + 1) + "Repeat", array2[i], D("boss_repeat", BossTitle(i))); } float[] array3 = new float[7] { 0f, 5f, 8f, 12f, 18f, 25f, 35f }; float[] array4 = new float[7] { 0f, 60f, 60f, 120f, 200f, 350f, 700f }; for (int j = 1; j <= 6; j++) { string text = ((j == 6) ? "Hybrid" : ("T" + j)); RankBase[j] = F("4. Prices", "RankBase" + text, array3[j], D("rank_base", text)); OpenPrice[j] = F("4. Prices", "Unlock" + text, array4[j], (j == 1) ? D("unlock_t1") : D("unlock", text)); } string[] array5 = new string[7] { "", "", "", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking" }; for (int k = 3; k <= 6; k++) { string text2 = ((k == 6) ? "Hybrid" : ("T" + k)); BossGate[k] = new SyncedString(cfg.Bind<string>("4. Prices", "BossFor" + text2, array5[k], D("boss_gate", text2))); } ForeignMult = F("4. Prices", "ForeignMult", 2f, D("ForeignMult")); Threshold = F("4. Prices", "Threshold", 9f, D("Threshold")); CoreRankBase = F("4. Prices", "CoreRankBase", 10f, D("CoreRankBase")); RespecItem = new SyncedString(cfg.Bind<string>("4. Prices", "RespecItem", "$item_greydwarfeye", D("RespecItem"))); RespecAmount = F("4. Prices", "RespecAmount", 10f, D("RespecAmount")); PowerPerRank = F("5. Effects", "PowerPerRank", 0.06f, D("PowerPerRank")); ManaPerRank = F("5. Effects", "ManaPerRank", 0.04f, D("ManaPerRank")); CooldownPerRank = F("5. Effects", "CooldownPerRank", 0.04f, D("CooldownPerRank")); ManaBase = F("5. Effects", "ManaBase", 40f, D("ManaBase")); ManaRegen = F("5. Effects", "ManaRegen", 0.6f, D("ManaRegen")); CoreManaPerRank = F("5. Effects", "CoreManaPerRank", 8f, D("CoreManaPerRank")); CoreRegenPerRank = F("5. Effects", "CoreRegenPerRank", 0.1f, D("CoreRegenPerRank")); CoreMightPerRank = F("5. Effects", "CoreMightPerRank", 0.02f, D("CoreMightPerRank")); RemoveVanillaMagic = F("5. Effects", "RemoveVanillaMagic", 1f, D("RemoveVanillaMagic")); UseEitr = F("5. Effects", "EitrToMana", 1f, D("EitrToMana")); Resonance = F("5. Effects", "WorldResonance", 0.25f, D("WorldResonance")); BossPercentMult = F("5. Effects", "BossPercentMult", 0.2f, D("BossPercentMult")); AllowPvp = F("5. Effects", "PvP", 1f, D("PvP")); MagicArmor = F("5. Effects", "MagicArmor", 0.5f, D("MagicArmor")); PvpControl = F("5. Effects", "PvpControl", 0.5f, D("PvpControl")); ShoutBonus = F("5. Effects", "ShoutBonus", 0.1f, D("ShoutBonus")); RestedRegen = F("5. Effects", "RestedManaRegen", 0.5f, D("RestedManaRegen")); AltarRegen = F("5. Effects", "AltarManaRegen", 1f, D("AltarManaRegen")); ProjectileSpeed = F("5. Effects", "ProjectileSpeed", 15f, D("ProjectileSpeed")); UseWeakness = F("5. Effects", "MobWeakness", 1f, D("MobWeakness")); SkillBonus = F("5. Effects", "SkillBonus", 0.25f, D("SkillBonus")); foreach (SpellDef item in SpellDefs.All) { string section = "6. Spell " + item.Id; item.CfgPower = F(section, "Power", item.Power, D("spell_power", item.PowerLabel)); item.CfgMana = F(section, "ManaCost", item.Mana, D("spell_mana")); item.CfgCooldown = F(section, "Cooldown", item.Cooldown, D("spell_cooldown")); Rebalance(item.CfgPower, item.Id + "/Power", item.Power); Rebalance(item.CfgMana, item.Id + "/ManaCost", item.Mana); Rebalance(item.CfgCooldown, item.Id + "/Cooldown", item.Cooldown); } } private static void Rebalance(SyncedFloat f, string key, float now) { if (f != null && OldDefaults.TryGetValue(key, out var value) && Mathf.Abs(f.Entry.Value - value) < 0.0001f && Mathf.Abs(value - now) > 0.0001f) { f.Entry.Value = now; Plugin.Log.LogInfo((object)("Rebalanced " + key + ": " + value + " -> " + now)); } } public static float KillReward(int biome) { if (KillByBiome.TryGetValue(biome, out var value)) { return value.Value; } return KillByBiome[1].Value; } public static HashSet<string> StopWordSet() { HashSet<string> hashSet = new HashSet<string>(); foreach (string item in VoiceLang.StopWords()) { string text = WordMatcher.Normalize(item); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } public static string Fmt(float v) { return v.ToString((v % 1f == 0f) ? "0" : "0.#", CultureInfo.InvariantCulture); } } public static class Lang { public sealed class Pack { public string Code = ""; public string Name = ""; public string File = ""; public string Dir = ""; public string ModelDir; public readonly List<string> Game = new List<string>(); public readonly List<string> StopWords = new List<string>(); public readonly List<KeyValuePair<string, string>> Fold = new List<KeyValuePair<string, string>>(); public readonly Dictionary<string, string> S = new Dictionary<string, string>(); public string Title { get { if (Name.Length <= 0) { return Code.ToUpperInvariant(); } return Name; } } } public static readonly List<Pack> Packs = new List<Pack>(); public static ConfigEntry<string> Setting; private static Pack _ui; private static int _mainThread = -1; private static readonly Regex FileRe = new Regex("^Galdr([A-Za-z]{2,8})\\.lang$", RegexOptions.IgnoreCase); private static readonly FieldInfo LocInstance = AccessTools.Field(typeof(Localization), "m_instance"); private static string _uiFor; private static float _uiCheck = -1f; private static bool OnMainThread { get { if (_mainThread >= 0) { return Thread.CurrentThread.ManagedThreadId == _mainThread; } return true; } } public static int Version { get; private set; } public static Pack Ui { get { string text = ((Setting != null) ? (Setting.Value ?? "").Trim() : "auto"); if (text.Length > 0 && !text.Equals("auto", StringComparison.OrdinalIgnoreCase)) { Pack pack = Find(text); if (pack != null) { return pack; } } if (!OnMainThread) { return _ui ?? Fallback(); } float realtimeSinceStartup = Time.realtimeSinceStartup; if (_ui != null && realtimeSinceStartup < _uiCheck) { return _ui; } _uiCheck = realtimeSinceStartup + 1f; string text2 = null; try { if (LocInstance != null && LocInstance.GetValue(null) != null) { text2 = Localization.instance.GetSelectedLanguage(); } } catch { } if (text2 == null) { return _ui ?? Fallback(); } if (_ui != null && text2 == _uiFor) { return _ui; } _uiFor = text2; Pack ui = _ui; _ui = ByGame(text2) ?? Fallback(); if (ui != null && ui != _ui) { Version++; } Plugin.Log.LogInfo((object)("Interface language: " + ((_ui != null) ? _ui.Code : "none") + " (game: " + text2 + ")")); return _ui; } } public static void Load() { _mainThread = Thread.CurrentThread.ManagedThreadId; Packs.Clear(); _ui = null; try { string pluginPath = Paths.PluginPath; if (Directory.Exists(pluginPath)) { Walk(pluginPath, 0); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Language packs: " + ex.Message)); } List<string> list = new List<string>(); foreach (Pack pack in Packs) { list.Add(pack.Code + " (" + pack.S.Count + " strings" + ((pack.ModelDir != null) ? ", voice" : "") + ")"); } Plugin.Log.LogInfo((object)("Language packs: " + ((list.Count == 0) ? "none" : string.Join(", ", list.ToArray())))); } private static void Walk(string dir, int depth) { if (depth > 4) { return; } try { string[] files = Directory.GetFiles(dir, "Galdr*.lang"); foreach (string text in files) { if (FileRe.IsMatch(Path.GetFileName(text))) { Parse(text); } } files = Directory.GetDirectories(dir); foreach (string text2 in files) { if (!Directory.Exists(Path.Combine(text2, "am")) || !Directory.Exists(Path.Combine(text2, "conf"))) { Walk(text2, depth + 1); } } } catch { } } private static void Parse(string file) { Pack pack = new Pack { File = file, Dir = Path.GetDirectoryName(file) }; Match match = FileRe.Match(Path.GetFileName(file)); pack.Code = match.Groups[1].Value.ToLowerInvariant(); string text = null; string[] array = File.ReadAllLines(file, Encoding.UTF8); for (int i = 0; i < array.Length; i++) { string text2 = array[i].TrimStart(new char[1] { '\ufeff' }); if (text2.Trim().Length == 0 || text2.TrimStart(Array.Empty<char>()).StartsWith("#")) { continue; } int num = text2.IndexOf('='); if (num <= 0) { continue; } string text3 = text2.Substring(0, num).Trim(); string text4 = Value(text2.Substring(num + 1)); if (text3.StartsWith("@")) { switch (text3.ToLowerInvariant()) { case "@code": if (text4.Trim().Length > 0) { pack.Code = text4.Trim().ToLowerInvariant(); } break; case "@name": pack.Name = text4.Trim(); break; case "@game": { string[] array2 = text4.Split(new char[1] { ',' }); foreach (string text7 in array2) { if (text7.Trim().Length > 0) { pack.Game.Add(text7.Trim()); } } break; } case "@stopwords": { string[] array2 = text4.Split(new char[1] { ',' }); foreach (string text6 in array2) { if (text6.Trim().Length > 0) { pack.StopWords.Add(text6.Trim()); } } break; } case "@fold": { string[] array2 = text4.Split(new char[1] { ',' }); foreach (string text5 in array2) { int num2 = text5.IndexOf('>'); if (num2 > 0) { pack.Fold.Add(new KeyValuePair<string, string>(text5.Substring(0, num2).Trim(), text5.Substring(num2 + 1).Trim())); } } break; } case "@model": text = text4.Trim(); break; } } else { pack.S[text3] = text4; } } if (!string.IsNullOrEmpty(text) && IsModel(Path.Combine(pack.Dir, text))) { pack.ModelDir = Path.Combine(pack.Dir, text); } else { try { array = Directory.GetDirectories(pack.Dir); foreach (string text8 in array) { if (IsModel(text8)) { pack.ModelDir = text8; break; } } } catch { } } if (Find(pack.Code) != null) { Plugin.Log.LogWarning((object)("Language pack " + pack.Code + " found twice, using the first: " + Find(pack.Code).File)); } else { Packs.Add(pack); } } public static bool IsModel(string dir) { if (Directory.Exists(dir) && Directory.Exists(Path.Combine(dir, "am"))) { return Directory.Exists(Path.Combine(dir, "conf")); } return false; } private static string Value(string v) { v = v.TrimEnd(new char[1] { '\r' }); if (v.StartsWith(" ")) { v = v.Substring(1); } string text = v.TrimEnd(Array.Empty<char>()); v = ((text.Length < 2 || text[0] != '"' || text[text.Length - 1] != '"') ? text : text.Substring(1, text.Length - 2)); if (v.IndexOf('\\') < 0) { return v; } StringBuilder stringBuilder = new StringBuilder(v.Length); for (int i = 0; i < v.Length; i++) { char c = v[i]; if (c == '\\' && i + 1 < v.Length) { char c2 = v[++i]; stringBuilder.Append(c2 switch { 't' => '\t', 'n' => '\n', _ => c2, }); } else { stringBuilder.Append(c); } } return stringBuilder.ToString(); } public static void Bind(ConfigFile cfg) { List<string> list = new List<string>(); foreach (Pack pack in Packs) { list.Add(pack.Code); } Setting = cfg.Bind<string>("0. Language", "Language", "auto", F("cfg.Language", (list.Count > 0) ? string.Join(", ", list.ToArray()) : T("cfg.Language_none"))); } public static Pack Find(string code) { if (string.IsNullOrEmpty(code)) { return null; } foreach (Pack pack in Packs) { if (string.Equals(pack.Code, code, StringComparison.OrdinalIgnoreCase)) { return pack; } } return null; } private static Pack ByGame(string g) { if (string.IsNullOrEmpty(g)) { return null; } foreach (Pack pack in Packs) { foreach (string item in pack.Game) { if (string.Equals(item, g, StringComparison.OrdinalIgnoreCase)) { return pack; } } } return null; } private static Pack Fallback() { Pack pack = Find("en"); if (pack == null) { if (Packs.Count <= 0) { return null; } pack = Packs[0]; } return pack; } public static string T(string key) { string text = Raw(key); if (text.IndexOf('{') >= 0 || text.IndexOf('}') >= 0) { return text.Replace("{{", "{").Replace("}}", "}"); } return text; } private static string Raw(string key) { Pack ui = Ui; if (ui != null && ui.S.TryGetValue(key, out var value)) { return value; } Pack pack = Find("en"); if (pack != null && pack != ui && pack.S.TryGetValue(key, out value)) { return value; } foreach (Pack pack2 in Packs) { if (pack2.S.TryGetValue(key, out value)) { return value; } } return key; } public static string F(string key, params object[] args) { string text = Raw(key); if (args == null || args.Length == 0) { return text.Replace("{{", "{").Replace("}}", "}"); } StringBuilder stringBuilder = new StringBuilder(text.Length + 32); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == '{' && i + 1 < text.Length && text[i + 1] == '{') { stringBuilder.Append('{'); i++; continue; } if (c == '}' && i + 1 < text.Length && text[i + 1] == '}') { stringBuilder.Append('}'); i++; continue; } if (c == '{') { int num = text.IndexOf('}', i + 1); if (num > i && int.TryParse(text.Substring(i + 1, num - i - 1), out var result)) { stringBuilder.Append((result >= 0 && result < args.Length && args[result] != null) ? args[result].ToString() : ""); i = num; continue; } } stringBuilder.Append(c); } return stringBuilder.ToString(); } public static string Plural(int n, string key) { string[] array = T(key).Split(new char[1] { '|' }); if (array.Length < 2) { return array[0]; } int num = Math.Abs(n); if (array.Length == 2) { if (num != 1) { return array[1]; } return array[0]; } int num2 = num % 10; int num3 = num % 100; if (num2 == 1 && num3 != 11) { return array[0]; } if (num2 >= 2 && num2 <= 4 && (num3 < 12 || num3 > 14)) { return array[1]; } return array[2]; } public static string Word(string w) { return F("fmt.word", w); } public static bool Has(string key) { foreach (Pack pack in Packs) { if (pack.S.ContainsKey(key)) { return true; } } return false; } } public sealed class Tx { public readonly string Key; private readonly object[] _args; public Tx(string key, params object[] args) { Key = key; _args = args; } public override string ToString() { return Lang.F(Key, _args); } public static implicit operator string(Tx t) { return t?.ToString(); } } public static class ArmorSets { private class Set { public string Name; public Element Element; public bool Mage; public string[] Keys; } public const float PowerPerPiece = 0.05f; public const float FullSetManaCut = 0.15f; public const int FullSet = 3; public const float MagePowerPerPiece = 0.03f; public const float MageRegenPerPiece = 0.1f; public const float WardPerPiece = 0.08f; public const float MageWardPerPiece = 0.04f; public const float FirePerkPower = 0.1f; public const float LightningPerkCd = 0.15f; public const float IcePerkTaken = 0.1f; public const float DarkPerkLeech = 0.15f; public const float LifePerkRegen = 0.15f; private static readonly Set[] Sets = new Set[11] { new Set { Name = "bronze", Element = Element.Fire, Keys = new string[2] { "HelmetBronze", "ArmorBronze" } }, new Set { Name = "flametal", Element = Element.Fire, Keys = new string[1] { "Flametal" } }, new Set { Name = "troll", Element = Element.Lightning, Keys = new string[2] { "TrollLeather", "CapeTrollHide" } }, new Set { Name = "fenris", Element = Element.Lightning, Keys = new string[1] { "Fenring" } }, new Set { Name = "iron", Element = Element.Ice, Keys = new string[2] { "HelmetIron", "ArmorIron" } }, new Set { Name = "wolf", Element = Element.Ice, Keys = new string[3] { "ArmorWolf", "HelmetDrake", "CapeWolf" } }, new Set { Name = "rags", Element = Element.Dark, Keys = new string[1] { "ArmorRags" } }, new Set { Name = "carapace", Element = Element.Dark, Keys = new string[1] { "Carapace" } }, new Set { Name = "leather", Element = Element.Life, Keys = new string[3] { "ArmorLeather", "HelmetLeather", "CapeDeerHide" } }, new Set { Name = "root", Element = Element.Life, Keys = new string[2] { "ArmorRoot", "HelmetRoot" } }, new Set { Name = "mage", Mage = true, Keys = new string[3] { "ArmorMage", "HelmetMage", "CapeFeather" } } }; private static readonly int[] Pieces = new int[5]; private static int _magePieces; private static float _nextCount; private static Player _countFor; private const string MarkTag = "<color=#ffca5e>"; private static readonly Dictionary<SharedData, KeyValuePair<string, string>> Orig = new Dictionary<SharedData, KeyValuePair<string, string>>(); private static string Mark => "<color=#ffca5e>" + Lang.T("armor.mark") + "</color>"; private static Set Match(string prefab) { if (string.IsNullOrEmpty(prefab)) { return null; } Set[] sets = Sets; foreach (Set set in sets) { string[] keys = set.Keys; foreach (string value in keys) { if (prefab.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return set; } } } return null; } private static bool IsArmor(SharedData sh) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 ItemType itemType = sh.m_itemType; if ((int)itemType != 6 && (int)itemType != 7 && (int)itemType != 11) { return (int)itemType == 17; } return true; } private static void Count(Player p) { if ((Object)(object)p == (Object)(object)_countFor && Time.time < _nextCount) { return; } _countFor = p; _nextCount = Time.time + 0.5f; for (int i = 0; i < 5; i++) { Pieces[i] = 0; } _magePieces = 0; if ((Object)(object)p == (Object)null || ((Humanoid)p).GetInventory() == null) { return; } foreach (ItemData equippedItem in ((Humanoid)p).GetInventory().GetEquippedItems()) { if (equippedItem == null || equippedItem.m_shared == null || !IsArmor(equippedItem.m_shared)) { continue; } Set set = Match(((Object)(object)equippedItem.m_dropPrefab != (Object)null) ? ((Object)equippedItem.m_dropPrefab).name : null); if (set != null) { if (set.Mage) { _magePieces++; } else { Pieces[(int)set.Element]++; } } } } private static int PiecesFor(SpellDef d) { if (d == null) { return 0; } if (!d.IsHybrid) { if (d.Element >= Element.Hybrid) { return 0; } return Pieces[(int)d.Element]; } return Mathf.Max(Pieces[(int)d.HybA], Pieces[(int)d.HybB]); } private static bool Perk(SpellDef d, Element e) { if (d == null || Pieces[(int)e] < 3) { return false; } if (!d.IsHybrid) { return d.Element == e; } if (d.HybA != e) { return d.HybB == e; } return true; } public static float PowerMult(SpellDef d) { Count(Player.m_localPlayer); return 1f + (float)PiecesFor(d) * 0.05f + (float)_magePieces * 0.03f + (Perk(d, Element.Fire) ? 0.1f : 0f); } public static float CooldownMult(SpellDef d) { Count(Player.m_localPlayer); if (!Perk(d, Element.Lightning)) { return 1f; } return 0.85f; } public static float DamageTakenMult(Player p) { Count(p); if (Pieces[2] < 3) { return 1f; } return 0.9f; } public static float WardMult(Player p, DmgType? type) { Count(p); int num = 0; if (type.HasValue) { num = type.Value switch { DmgType.Fire => Pieces[0], DmgType.Frost => Pieces[2], DmgType.Lightning => Pieces[1], _ => Pieces[3] + Pieces[4], }; } float num2 = Mathf.Min(0.4f, (float)num * 0.08f) + (float)_magePieces * 0.04f; return Mathf.Clamp(1f - num2, 0.5f, 1f); } public static void OnSpellDamage(CastContext c, float amount) { if (c == null || (Object)(object)c.P == (Object)null || (Object)(object)c.P != (Object)(object)Player.m_localPlayer || amount <= 0f) { return; } Count(c.P); if (Perk(c.D, Element.Dark)) { MagicController instance = MagicController.Instance; if (!((Object)(object)instance == (Object)null)) { instance.Mana = Mathf.Min(instance.MaxMana(), instance.Mana + amount * 0.15f); } } } public static float ManaMult(SpellDef d) { Count(Player.m_localPlayer); if (PiecesFor(d) < 3) { return 1f; } return 0.85f; } public static float RegenBonus(Player p) { Count(p); return (float)_magePieces * 0.1f + ((Pieces[4] >= 3) ? 0.15f : 0f); } public static int HeavyForeign(Player p) { if ((Object)(object)p == (Object)null || ((Humanoid)p).GetInventory() == null) { return 0; } MagicController instance = MagicController.Instance; int num = (((Object)(object)instance != (Object)null && instance.Data != null) ? instance.Data.native : (-1)); int num2 = 0; foreach (ItemData equippedItem in ((Humanoid)p).GetInventory().GetEquippedItems()) { if (equippedItem != null && equippedItem.m_shared != null && IsArmor(equippedItem.m_shared) && !(equippedItem.m_shared.m_movementModifier >= -0.001f)) { Set set = Match(((Object)(object)equippedItem.m_dropPrefab != (Object)null) ? ((Object)equippedItem.m_dropPrefab).name : null); if (set == null || (!set.Mage && set.Element != (Element)num)) { num2++; } } } return num2; } public static void Relocalize() { foreach (KeyValuePair<SharedData, KeyValuePair<string, string>> item in new List<KeyValuePair<SharedData, KeyValuePair<string, string>>>(Orig)) { item.Key.m_description = item.Value.Key; Append(item.Key, item.Value.Value); } } public static void Describe(ObjectDB db) { if ((Object)(object)db == (Object)null || db.m_items == null) { return; } foreach (GameObject item in db.m_items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null) && val.m_itemData != null && val.m_itemData.m_shared != null) { SharedData shared = val.m_itemData.m_shared; if (IsArmor(shared) && (shared.m_description == null || !shared.m_description.Contains("<color=#ffca5e>"))) { Orig[shared] = new KeyValuePair<string, string>(shared.m_description, ((Object)item).name); Append(shared, ((Object)item).name); } } } } private static void Append(SharedData sh, string prefabName) { Set set = Match(prefabName); bool flag = sh.m_movementModifier < -0.001f && (set == null || !set.Mage); if (set == null) { if (flag) { sh.m_description = sh.m_description + "\n\n" + Lang.F("armorsets.heavy_line", Mark, Mathf.RoundToInt(5f)); } return; } string text; if (set.Mage) { text = Lang.F("armorsets.mage_set", Pct(0.03f), Pct(0.1f), Pct(0.04f)); } else { Element e = ((set.Element == Element.Life) ? Element.Dark : set.Element); string text2 = Lang.F("armorsets.piece", SpellDefs.ElementName(set.Element), Pct(0.05f), SpellDefs.ElementName(e), Pct(0.08f)); object[] obj = new object[2] { Mathf.RoundToInt(15.000001f), null }; int element = (int)set.Element; obj[1] = Lang.T("armorsets.perk." + element); text = text2 + "\n" + Lang.F("armorsets.set3", obj); } if (flag) { text = text + "\n" + Lang.F("armorsets.heavy_foreign", Mathf.RoundToInt(5f)); } sh.m_description = sh.m_description + "\n\n" + Mark + " " + text; } private static string Pct(float f) { return "<color=orange>" + Mathf.RoundToInt(f * 100f) + "%</color>"; } public static string Summary(SpellDef d) { float num = PowerMult(d); float num2 = ManaMult(d); float num3 = CooldownMult(d); bool flag = Perk(d, Element.Dark); if (num <= 1.0001f && num2 >= 0.9999f && num3 >= 0.9999f && !flag) { return null; } string text = Lang.F("armorsets.summary_power", Mathf.RoundToInt((num - 1f) * 100f)); if (num2 < 0.9999f) { text += Lang.F("armorsets.summary_mana", Mathf.RoundToInt((1f - num2) * 100f)); } if (num3 < 0.9999f) { text += Lang.F("armorsets.cooldown", Mathf.RoundToInt((1f - num3) * 100f)); } if (flag) { text += Lang.F("armorsets.leech", Mathf.RoundToInt(15.000001f)); } return text; } } public static class Chronicle { private const string Red = "<color=#6b1d0c>"; private const string End = "</color>"; private static PlayerMagicData D { get { if (!((Object)(object)MagicController.Instance != (Object)null)) { return null; } return MagicController.Instance.Data; } } private static void Dirty() { if ((Object)(object)MagicController.Instance != (Object)null) { MagicController.Instance.MarkDirtySoft(); } } public static void Cast(SpellDef d, float mana, MagicController.Loud loud) { PlayerMagicData d2 = D; if (d2 != null && d != null) { d2.casts.TryGetValue(d.Id, out var value); d2.casts[d.Id] = value + 1; d2.manaSpent += Mathf.Max(0f, mana); switch (loud) { case MagicController.Loud.Shout: d2.shouts++; break; case MagicController.Loud.Whisper: d2.whispers++; break; } if (d2.firstCast == 0L) { d2.firstCast = DateTime.UtcNow.Ticks; } Dirty(); } } public static void Misfire(float mana) { PlayerMagicData d = D; if (d != null) { d.misfires++; d.manaSpent += Mathf.Max(0f, mana); Dirty(); } } public static void Hit(SpellDef d, float amount) { PlayerMagicData d2 = D; if (d2 != null && d != null && !(amount <= d2.bestHit)) { d2.bestHit = amount; d2.bestHitSpell = d.Id; Dirty(); } } public static void Kill() { PlayerMagicData d = D; if (d != null) { d.kills++; Dirty(); } } private static string Name(string id) { SpellDef spellDef = SpellDefs.Get(id); if (spellDef != null) { return spellDef.Name; } return "?"; } public static BookText.Page Page() { PlayerMagicData d = D; if (d == null || d.casts.Count == 0) { return null; } int num = 0; string text = null; int num2 = 0; int[] array = new int[5]; int num3 = 0; foreach (KeyValuePair<string, int> cast in d.casts) { num += cast.Value; if (cast.Value > num2) { num2 = cast.Value; text = cast.Key; } SpellDef spellDef = SpellDefs.Get(cast.Key); if (spellDef != null) { if (spellDef.IsHybrid) { num3 += cast.Value; } else { array[(int)spellDef.Element] += cast.Value; } } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("<i>").Append(Lang.T("chron.intro")).Append("</i>\n\n"); if (d.firstCast > 0) { stringBuilder.Append(Lang.F("chron.since", new DateTime(d.firstCast, DateTimeKind.Utc).ToLocalTime().ToString(Lang.T("fmt.date"), CultureInfo.InvariantCulture))).Append('\n'); } stringBuilder.Append(Lang.F("chron.casts", "<color=#6b1d0c>", num, "</color>")).Append('\n'); if (text != null) { stringBuilder.Append(Lang.F("chron.favorite", "<color=#6b1d0c>", Name(text), "</color>", num2, Lang.Plural(num2, "plural.times"))).Append('\n'); } stringBuilder.Append('\n'); Element[] ring = SpellDefs.Ring; foreach (Element element in ring) { if (array[(int)element] > 0) { stringBuilder.Append(Lang.F("chron.element", SpellDefs.ElementName(element), array[(int)element])).Append('\n'); } } if (num3 > 0) { stringBuilder.Append(Lang.F("chron.element", Lang.T("booktext.two_elements"), num3)).Append('\n'); } stringBuilder.Append('\n'); stringBuilder.Append(Lang.F("chron.kills", "<color=#6b1d0c>", d.kills, "</color>")).Append('\n'); if (d.bestHit > 0f && !string.IsNullOrEmpty(d.bestHitSpell)) { stringBuilder.Append(Lang.F("chron.best", "<color=#6b1d0c>", Mathf.RoundToInt(d.bestHit), "</color>", Name(d.bestHitSpell))).Append('\n'); } stringBuilder.Append(Lang.F("chron.mana", Mathf.RoundToInt(d.manaSpent))).Append('\n'); if (d.shouts > 0 || d.whispers > 0) { stringBuilder.Append(Lang.F("chron.loud", d.shouts, d.whispers)).Append('\n'); } if (d.quick > 0) { stringBuilder.Append(Lang.F("chron.quick", d.quick)).Append('\n'); } if (d.misfires > 0) { stringBuilder.Append(Lang.F("chron.misfires", d.misfires)).Append('\n'); } return new BookText.Page { Title = Lang.T("chron.title"), Body = stringBuilder.ToString().TrimEnd(Array.Empty<char>()), Small = true }; } } public static class Foci { public class Fx { public Element El; public float Power; public float Cooldown; public float Regen; public float OthersPower; public bool HasWeak; public Element Weak; public float WeakPower; public float KillMana; public float HpRegen = 1f; } public static readonly Dictionary<string, Fx> ById = new Dictionary<string, Fx> { { "GaldrFocus_Fire1", new Fx { El = Element.Fire, Power = 0.2f, HasWeak = true, Weak = Element.Ice, WeakPower = 0.3f } }, { "GaldrFocus_Fire2", new Fx { El = Element.Fire, Power = 0.3f, Cooldown = 0.1f, HasWeak = true, Weak = Element.Ice, WeakPower = 0.5f } }, { "GaldrFocus_Lightning1", new Fx { El = Element.Lightning, Power = 0.15f, Cooldown = 0.15f, Regen = 0.15f } }, { "GaldrFocus_Lightning2", new Fx { El = Element.Lightning, Power = 0.25f, Cooldown = 0.2f, Regen = 0.25f } }, { "GaldrFocus_Ice1", new Fx { El = Element.Ice, Power = 0.2f, HasWeak = true, Weak = Element.Fire, WeakPower = 0.3f } }, { "GaldrFocus_Ice2", new Fx { El = Element.Ice, Power = 0.3f, Cooldown = 0.1f, HasWeak = true, Weak = Element.Fire, WeakPower = 0.5f } }, { "GaldrFocus_Dark1", new Fx { El = Element.Dark, Power = 0.2f, KillMana = 3f, HpRegen = 0.75f } }, { "GaldrFocus_Dark2", new Fx { El = Element.Dark, Power = 0.3f, KillMana = 6f, HpRegen = 0.6f, HasWeak = true, Weak = Element.Life, WeakPower = 0.3f } }, { "GaldrFocus_Life1", new Fx { El = Element.Life, Power = 0.25f, OthersPower = 0.15f } }, { "GaldrFocus_Life2", new Fx { El = Element.Life, Power = 0.35f, Cooldown = 0.1f, OthersPower = 0.25f } } }; private static Fx _cur; private static float _next; private static Player _for; public static Fx Current() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)(object)_for && Time.time < _next) { return _cur; } _for = localPlayer; _next = Time.time + 0.5f; _cur = null; if ((Object)(object)localPlayer == (Object)null || ((Humanoid)localPlayer).GetInventory() == null) { return null; } foreach (ItemData equippedItem in ((Humanoid)localPlayer).GetInventory().GetEquippedItems()) { ManaFoods.Def def = ManaFoods.Of(equippedItem); if (def != null && def.Kind == ManaFoods.Kind.Focus && ById.TryGetValue(def.Id, out var value)) { _cur = value; break; } } return _cur; } public static bool Equipped(Element e) { Fx fx = Current(); if (fx != null) { return fx.El == e; } return false; } private static bool Touches(SpellDef d, Element e) { if (!d.IsHybrid) { return d.Element == e; } if (d.HybA != e) { return d.HybB == e; } return true; } public static float PowerMult(SpellDef d) { Fx fx = Current(); if (fx == null || d == null || d.Tier == 0) { return 1f; } float num = 1f; num = ((!Touches(d, fx.El)) ? (num - fx.OthersPower) : (num + fx.Power)); if (fx.HasWeak && Touches(d, fx.Weak) && !Touches(d, fx.El)) { num -= fx.WeakPower; } return Mathf.Max(0.2f, num); } public static float CooldownMult(SpellDef d) { Fx fx = Current(); if (fx == null || d == null || d.Tier == 0 || !Touches(d, fx.El)) { return 1f; } return 1f - fx.Cooldown; } public static float RegenPenalty() { return Current()?.Regen ?? 0f; } public static void OnKill() { Fx fx = Current(); MagicController instance = MagicController.Instance; if (fx != null && !(fx.KillMana <= 0f) && !((Object)(object)instance == (Object)null) && instance.Data != null) { instance.Mana = Mathf.Min(instance.MaxMana(), instance.Mana + fx.KillMana); } } public static string Summary(SpellDef d) { if (Current() == null || d == null) { return null; } float num = PowerMult(d); float num2 = CooldownMult(d); if (Mathf.Abs(num - 1f) < 0.001f && num2 > 0.999f) { return null; } string text = Lang.F("foci.summary", (num >= 1f) ? "+" : "−", Mathf.RoundToInt(Mathf.Abs(num - 1f) * 100f)); if (num2 < 0.999f) { text += Lang.F("foci.summary_cooldown", Mathf.RoundToInt((1f - num2) * 100f)); } return text; } public static string Describe(string id) { if (!ById.TryGetValue(id, out var value)) { return ""; } string text = SpellDefs.ElementName(value.El).ToLowerInvariant(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Lang.F("foci.line_power", text, Mathf.RoundToInt(value.Power * 100f))); if (value.Cooldown > 0f) { stringBuilder.Append(Lang.F("foci.line_cooldown", Mathf.RoundToInt(value.Cooldown * 100f))); } if (value.KillMana > 0f) { stringBuilder.Append(Lang.F("foci.line_killmana", value.KillMana)); } stringBuilder.Append("\n<color=#d06050>"); List<string> list = new List<string>(); if (value.HasWeak) { list.Add(Lang.F("foci.line_weak", SpellDefs.ElementName(value.Weak).ToLowerInvariant(), Mathf.RoundToInt(value.WeakPower * 100f))); } if (value.OthersPower > 0f) { list.Add(Lang.F("foci.line_others", Mathf.RoundToInt(value.OthersPower * 100f))); } if (value.Regen > 0f) { list.Add(Lang.F("foci.line_mana_slower", Mathf.RoundToInt(value.Regen * 100f))); } if (value.HpRegen < 1f) { list.Add(Lang.F("foci.line_hp_slower", Mathf.RoundToInt((1f - value.HpRegen) * 100f))); } if (value.El == Element.Fire) { list.Add(Lang.T("foci.rain_dulls_fire_even_more")); } stringBuilder.Append(string.Join("\n", list.ToArray())).Append("</color>"); return stringBuilder.ToString(); } public static StatusEffect EquipEffect(string id, string name) { if (!ById.TryGetValue(id, out var value) || value.HpRegen >= 1f) { return null; } SE_Stats obj = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)obj).name = "SE_" + id; ((StatusEffect)obj).m_name = name; ((StatusEffect)obj).m_tooltip = Lang.T("foci.health_regenerates_slower"); obj.m_healthRegenMultiplier = value.HpRegen; ((StatusEffect)obj).m_icon = GameArt.Element(value.El); return (StatusEffect)(object)obj; } } public static class ManaFoods { public enum Kind { Food, Charm, Scroll, Book, Notes, Potion, Focus, Trick } public class Def { public string Id; public string Name; public string Source; public string Station; public string Icon; public string Desc; public string[] IconSrc; public Color Tint = Color.white; public Color Glow = Color.clear; public float TintAmt; public float GlowStr; public Kind Kind; public float Mana; public float Regen; public float Health; public float Stamina; public float HpRegen; public float Duration; public float Knowledge; public int MaxQuality = 1; public int StationLevel = 1; public string[] Res; public Element El; public int Level = 1; public string Trick; public GameObject Prefab; } private static readonly Color ManaTint = new Color(0.45f, 0.62f, 1f); private static readonly Color ManaGlow = new Color(0.4f, 0.6f, 1f, 0.8f); public static readonly List<Def> All = new List<Def> { new Def { Id = "GaldrFood_Meadows", Source = "QueensJam", Station = "piece_workbench", Icon = "food_meadows", Mana = 20f, Regen = 0.15f, Health = 12f, Stamina = 10f, HpRegen = 1f, Duration = 900f, Tint = ManaTint, TintAmt = 0.3f, Glow = ManaGlow, GlowStr = 1.3f, Res = new string[2] { "Dandelion:4", "Raspberry:3" } }, new Def { Id = "GaldrFood_BlackForest", Source = "CarrotSoup", Station = "piece_cauldron", Icon = "food_blackforest", Mana = 35f, Regen = 0.25f, Health = 16f, Stamina = 14f, HpRegen = 1f, Duration = 1200f, Tint = ManaTint, TintAmt = 0.4f, Glow = ManaGlow, GlowStr = 1.3f, Res = new string[3] { "Mushroom:2", "Blueberries:3", "Thistle:1" } }, new Def { Id = "GaldrFood_Swamp", Source = "BlackSoup", Station = "piece_cauldron", Icon = "food_swamp", Mana = 50f, Regen = 0.35f, Health = 21f, Stamina = 18f, HpRegen = 2f, Duration = 1500f, Tint = new Color(0.7f, 0.45f, 1f), TintAmt = 0.3f, Glow = ManaGlow, GlowStr = 1.3f, Res = new string[3] { "Bloodbag:1", "Turnip:2", "Thistle:2" } }, new Def { Id = "GaldrFood_Mountain", Source = "OnionSoup", Station = "piece_cauldron", Icon = "food_mountain", Mana = 70f, Regen = 0.45f, Health = 26f, Stamina = 22f, HpRegen = 2f, Duration = 1500f, Tint = new Color(0.55f, 0.85f, 1f), TintAmt = 0.45f, Glow = new Color(0.55f, 0.85f, 1f, 0.85f), GlowStr = 1.4f, Res = new string[3] { "Honey:2", "Onion:2", "FreezeGland:1" } }, new Def { Id = "GaldrFood_Plains", Source = "Bread", Station = "piece_cauldron", Icon = "food_plains", Mana = 90f, Regen = 0.55f, Health = 31f, Stamina = 26f, HpRegen = 3f, Duration = 1800f, Tint = ManaTint, TintAmt = 0.25f, Glow = ManaGlow, GlowStr = 1.5f, Res = new string[3] { "BarleyFlour:2", "Cloudberry:3", "Honey:1" } }, new Def { Id = "GaldrFood_Meadows2", Source = "Raspberry", Station = "piece_workbench", Icon = "food_meadows2", Mana = 12f, Regen = 0.3f, Health = 9f, Stamina = 9f, HpRegen = 1f, Duration = 900f, Tint = ManaTint, TintAmt = 0.25f, Glow = ManaGlow, GlowStr = 1.2f, Res = new string[2] { "Raspberry:6", "Honey:1" } }, new Def { Id = "GaldrFood_BlackForest2", Source = "MushroomYellow", Station = "piece_cauldron", Icon = "food_blackforest2", Mana = 20f, Regen = 0.45f, Health = 13f, Stamina = 12f, HpRegen = 1f, Duration = 1200f, Tint = ManaTint, TintAmt = 0.35f, Glow = ManaGlow, GlowStr = 1.2f, Res = new string[3] { "Mushroom:2", "MushroomYellow:2", "Thistle:1" } }, new Def { Id = "GaldrFood_Swamp2", Source = "TurnipStew", Station = "piece_cauldron", Icon = "food_swamp2", Mana = 30f, Regen = 0.6f, Health = 17f, Stamina = 15f, HpRegen = 2f, Duration = 1500f, Tint = new Color(0.6f, 0.5f, 1f), TintAmt = 0.3f, Glow = ManaGlow, GlowStr = 1.2f, Res = new string[3] { "Turnip:3", "Mushroom:2", "Thistle:1" } }, new Def { Id = "GaldrFood_Mountain2", Source = "Eyescream", Station = "piece_cauldron", Icon = "food_mountain2", Mana = 40f, Regen = 0.75f, Health = 21f, Stamina = 18f, HpRegen = 2f, Duration = 1500f, Tint = new Color(0.55f, 0.85f, 1f), TintAmt = 0.4f, Glow = new Color(0.55f, 0.85f, 1f, 0.85f), GlowStr = 1.3f, Res = new string[3] { "FreezeGland:1", "GreydwarfEye:3", "Honey:1" } }, new Def { Id = "GaldrFood_Plains2", Source = "BloodPudding", Station = "piece_cauldron", Icon = "food_plains2", Mana = 55f, Regen = 0.9f, Health = 25f, Stamina = 21f, HpRegen = 3f, Duration = 1800f, Tint = new Color(1f, 0.75f, 0.4f), TintAmt = 0.35f, Glow = ManaGlow, GlowStr = 1.3f, Res = new string[3] { "Cloudberry:4", "Barley:2", "Honey:1" } }, new Def { Id = "GaldrFood_Mistlands", Source = "MagicallyStuffedShroom", Station = "piece_cauldron", Icon = "food_mistlands", Mana = 120f, Regen = 0.7f, Health = 36f, Stamina = 30f, HpRegen = 3f, Duration = 1800f, Tint = new Color(0.7f, 0.55f, 1f), TintAmt = 0.3f, Glow = new Color(0.7f, 0.5f, 1f, 0.85f), GlowStr = 1.4f, Res = new string[3] { "Sap:1", "MushroomJotunPuffs:2", "MushroomMagecap:1" } }, new Def { Id = "GaldrPotion1", Source = "MeadHealthMinor", Station = "piece_cauldron", Icon = "potion1", Kind = Kind.Potion, Mana = 40f, Tint = new Color(0.35f, 0.55f, 1f), TintAmt = 0.85f, Glow = ManaGlow, GlowStr = 1.2f, Res = new string[3] { "Dandelion:4", "Raspberry:2", "Honey:1" } }, new Def { Id = "GaldrPotion2", Source = "MeadHealthMedium", Station = "piece_cauldron", Icon = "potion2", Kind = Kind.Potion, Mana = 80f, Tint = new Color(0.35f, 0.55f, 1f), TintAmt = 0.85f, Glow = ManaGlow, GlowStr = 1.3f, Res = new string[3] { "Thistle:2", "Bloodbag:1", "Turnip:1" } }, new Def { Id = "GaldrPotion3", Source = "MeadHealthMajor", Station = "piece_cauldron", Icon = "potion3", Kind = Kind.Potion, Mana = 150f, Tint = new Color(0.55f, 0.45f, 1f), TintAmt = 0.85f, Glow = new Color(0.6f, 0.5f, 1f, 0.9f), GlowStr = 1.5f, Res = new string[2] { "Sap:1", "MushroomMagecap:2" } }, new Def { Id = "GaldrNotes1", Source = "LeatherScraps", Icon = "notes1", Kind = Kind.Notes, Knowledge = 20f, Tint = new Color(0.8f, 0.7f, 0.55f), TintAmt = 0.3f, Glow = new Color(1f, 0.7f, 0.3f, 0.5f), GlowStr = 0.8f }, new Def { Id = "GaldrNotes2", Source = "LeatherScraps", Icon = "notes2", Kind = Kind.Notes, Knowledge = 50f, Tint = new Color(0.45f, 0.75f, 0.45f), TintAmt = 0.45f, Glow = new Color(0.5f, 1f, 0.5f, 0.5f), GlowStr = 0.9f }, new Def { Id = "GaldrNotes3", Source = "LeatherScraps", Icon = "notes3", Kind = Kind.Notes, Knowledge = 110f, Tint = new Color(0.9f, 0.35f, 0.3f), TintAmt = 0.45f, Glow = new Color(1f, 0.4f, 0.3f, 0.5f), GlowStr = 1f }, new Def { Id = "GaldrCharm", Source = "BeltStrength", Station = "piece_workbench", Icon = "charm", Kind = Kind.Charm, MaxQuality = 4, StationLevel = 2, IconSrc = new string[2] { "SilverNecklace", "Wishbone" }, Tint = new Color(1f, 0.8f, 0.45f), TintAmt = 0.3f, Glow = new Color(0.55f, 0.75f, 1f, 0.8f), GlowStr = 1.4f, Res = new string[5] { "LeatherScraps:5:0", "Resin:5:0", "GreydwarfEye:4:0", "Bronze:0:3", "TrophyGreydwarf:0:1" } }, new Def { Id = "GaldrMead1", Source = "MeadTasty", Station = "piece_cauldron", Icon = "scroll1", Kind = Kind.Scroll, Knowledge = 25f, Tint = new Color(1f, 0.75f, 0.3f), TintAmt = 0.45f, Glow = new Color(1f, 0.7f, 0.3f, 0.7f), GlowStr = 1.3f, Res = new string[3] { "Honey:2", "GreydwarfEye:3", "TrophyGreydwarf:1" } }, new Def { Id = "GaldrMead2", Source = "MeadTasty", Station = "piece_cauldron", Icon = "scroll2", Kind = Kind.Scroll, Knowledge = 70f, Tint = new Color(0.75f, 0.5f, 1f), TintAmt = 0.55f, Glow = new Color(0.7f, 0.45f, 1f, 0.8f), GlowStr = 1.4f, Res = new string[4] { "Honey:2", "TrophyDraugr:1", "TrophySkeleton:1", "Bloodbag:2" } }, new Def { Id = "GaldrMead3", Source = "MeadTasty", Station = "piece_cauldron", Icon = "scroll3", Kind = Kind.Scroll, Knowledge = 180f, Tint = new Color(0.6f, 0.9f, 1f), TintAmt = 0.55f, Glow = new Color(0.6f, 0.9f, 1f, 0.9f), GlowStr = 1.6f, Res = new string[3] { "Honey:2", "TrophyGoblin:2", "TrophyFenring:1" } }, Focus("GaldrFocus_Fire1", Element.Fire, 1, "piece_workbench", 3, "SurtlingCore:2", "Coal:10", "Bronze:2"), Focus("GaldrFocus_Fire2", Element.Fire, 2, "forge", 3, "SurtlingCore:6", "Obsidian:6", "BlackMetal:3"), Focus("GaldrFocus_Lightning1", Element.Lightning, 1, "piece_workbench", 2, "HardAntler:1", "Bronze:2", "LeatherScraps:4"), Focus("GaldrFocus_Lightning2", Element.Lightning, 2, "forge", 3, "DragonTear:2", "Silver:4", "Crystal:3"), Focus("GaldrFocus_Ice1", Element.Ice, 1, "forge", 2, "WolfFang:4", "FreezeGland:3", "Silver:2"), Focus("GaldrFocus_Ice2", Element.Ice, 2, "forge", 3, "DragonTear:3", "FreezeGland:6", "Silver:6"), Focus("GaldrFocus_Dark1", Element.Dark, 1, "piece_workbench", 3, "TrophyDraugr:1", "Ooze:5", "Iron:2"), Focus("GaldrFocus_Dark2", Element.Dark, 2, "forge", 3, "Wishbone:1", "Ooze:10", "BlackMetal:3"), Focus("GaldrFocus_Life1", Element.Life, 1, "piece_workbench", 2, "AncientSeed:3", "FineWood:5", "Resin:10"), Focus("GaldrFocus_Life2", Element.Life, 2, "piece_workbench", 4, "YggdrasilWood:6", "Sap:3", "Resin:20"), Trick("meteor"), Trick("chain"), Trick("drain"), Trick("shards"), Trick("heal"), Trick("blast"), Trick("freeze"), new Def { Id = "GaldrBook", Source = "LeatherScraps", Icon = "book", Kind = Kind.Book } }; private static readonly Dictionary<string, Def> ByItemName = new Dictionary<string, Def>(); private static GameObject _holder; private static readonly MethodInfo Clone = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic); private const string TrinketSource = "*trinket"; private static string _trinket; public const float PotionCooldown = 60f; private static float _potionReadyAt; private static Def Focus(string id, Element el, int level, string station, int stationLevel, params string[] res) { return new Def { Id = id, El = el, Level = level, Kind = Kind.Focus, Source = "*trinket", Station = station, StationLevel = stationLevel, Res = res }; } private static Def Trick(string id) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) return new Def { Id = "GaldrTrick_" + id, Source = "LeatherScraps", Kind = Kind.Trick, Trick = id, Tint = new Color(0.55f, 0.75f, 1f), TintAmt = 0.45f, Glow = new Color(0.5f, 0.8f, 1f, 0.6f), GlowStr = 1f }; } private static void FindTrinket(IEnumerable<GameObject> items) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 if (_trinket != null || items == null) { return; } string text = null; foreach (GameObject item in items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null) && val.m_itemData != null && val.m_itemData.m_shared != null && (int)val.m_itemData.m_shared.m_itemType == 24 && !((Object)item).name.StartsWith("Galdr")) { if (text == null) { text = ((Object)item).name; } if (((Object)item).name.IndexOf("Bronze", StringComparison.OrdinalIgnoreCase) >= 0) { text = ((Object)item).name; break; } } } _trinket = text; if (_trinket != null) { Plugin.Log.LogInfo((object)("Foci: base item — " + _trinket)); } } private static void Localize(Def d) { if (d.Kind == Kind.Book) { d.Name = GuideBook.ItemName; d.Desc = Lang.T("item.book.desc"); } else if (d.Kind == Kind.Trick) { Tricks.Def def = Tricks.ById(d.Trick); d.Name = Lang.F("item.trick.name", (def != null) ? ((string)def.Name) : d.Trick); d.Desc = Lang.T("item.trick.desc"); } else { d.Name = Lang.T("item." + d.Id + ".name"); d.Desc = Lang.T("item." + d.Id + ".desc"); } } public static void Relocalize() { foreach (Def item in All) { if ((Object)(object)item.Prefab == (Object)null) { continue; } ItemDrop component = item.Prefab.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null) { Localize(item); SharedData shared = component.m_itemData.m_shared; shared.m_name = item.Name; shared.m_description = Describe(item); if ((Object)(object)shared.m_equipStatusEffect != (Object)null && item.Kind == Kind.Focus) { shared.m_equipStatusEffect.m_name = item.Name; } } } } private static string Describe(Def d) { string text = (string.IsNullOrEmpty(d.Desc) ? "" : (d.Desc + "\n\n")); switch (d.Kind) { case Kind.Charm: return text + Lang.T("manafoods.galdr_power_5_per_level"); case Kind.Scroll: return text + Lang.F("manafoods.desc_knowledge", d.Knowledge); case Kind.Book: return text + Lang.T("manafoods.use_to_read"); case Kind.Notes: return text + Lang.F("manafoods.desc_knowledge", d.Knowledge); case Kind.Focus: return text + Foci.Describe(d.Id); case Kind.Trick: { Tricks.Def def = Tricks.ById(d.Trick); return text + ((def != null) ? string.Concat("<color=orange>", def.Desc, "</color>") : ""); } case Kind.Potion: return text + Lang.F("manafoods.desc_potion", d.Mana, 60f); default: return text + Lang.F("manafoods.desc_food", d.Mana, d.Regen.ToString("0.##")); } } private static void Build(Func<string, GameObject> lookup) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) foreach (Def item in All) { if ((Object)(object)item.Prefab != (Object)null) { continue; } string text = ((item.Source == "*trinket") ? _trinket : item.Source); if (text == null) { continue; } GameObject val = lookup(text); if ((Object)(object)val == (Object)null) { continue; } if ((Object)(object)_holder == (Object)null) { _holder = new GameObject("GaldrItems"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); } GameObject val2 = Object.Instantiate<GameObject>(val, _holder.transform); ((Object)val2).name = item.Id; Localize(item); ItemDrop component = val2.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); continue; } SharedData val3 = (SharedData)Clone.Invoke(component.m_itemData.m_shared, null); val3.m_name = item.Name; val3.m_description = Describe(item); Sprite val4 = null; if (item.IconSrc != null) { string[] iconSrc = item.IconSrc; foreach (string arg in iconSrc) { GameObject val5 = lookup(arg); ItemDrop val6 = (((Object)(object)val5 != (Object)null) ? val5.GetComponent<ItemDrop>() : null); if ((Object)(object)val6 != (Object)null && val6.m_itemData.m_shared.m_icons != null && val6.m_itemData.m_shared.m_icons.Length != 0) { val4 = val6.m_itemData.m_shared.m_icons[0]; break; } } } if ((Object)(object)val4 == (Object)null && val3.m_icons != null && val3.m_icons.Length != 0) { val4 = val3.m_icons[0]; } if (item.Kind == Kind.Focus) { Sprite val7 = GameArt.Element(item.El); val4 = null; if ((Object)(object)val7 != (Object)null) { val3.m_icons = (Sprite[])(object)new Sprite[1] { (item.Level >= 2) ? GameArt.Recolor(val7, item.Id, new Color(1f, 0.85f, 0.5f), 0.15f, new Color(1f, 0.8f, 0.4f, 0.8f), 1.5f) : val7 }; } } if ((Object)(object)val4 != (Object)null && item.Kind != Kind.Book && item.Kind != Kind.Notes && item.Kind != Kind.Trick) { Sprite val8 = GameArt.Recolor(val4, item.Id, item.Tint, item.TintAmt, item.Glow, item.GlowStr); if ((Object)(object)val8 != (Object)null) { val3.m_icons = (Sprite[])(object)new Sprite[1] { val8 }; } } switch (item.Kind) { case Kind.Food: val3.m_food = item.Health; val3.m_foodStamina = item.Stamina; val3.m_foodEitr = 0f; val3.m_foodRegen = item.HpRegen; val3.m_foodBurnTime = item.Duration; val3.m_maxStackSize = 10; break; case Kind.Charm: val3.m_equipStatusEffect = null; val3.m_movementModifier = 0f; val3.m_maxQuality = item.MaxQuality; break; case Kind.Book: GuideBook.SetupPrefab(val2, component, val3); break; case Kind.Focus: val3.m_maxAdrenaline = 0f; val3.m_fullAdrenalineSE = null; val3.m_blockAdrenaline = 0f; val3.m_perfectBlockAdrenaline = 0f; val3.m_equipStatusEffect = Foci.EquipEffect(item.Id, item.Name); val3.m_movementModifier = 0f; val3.m_maxQuality = 1; val3.m_maxStackSize = 1; break; case Kind.Trick: { GuideBook.SetupPrefab(val2, component, val3); val3.m_maxStackSize = 5; val3.m_weight = 0.3f; val3.m_icons = (Sprite[])(object)new Sprite[1] { GameArt.Recolor(BookArt.Icon(), item.Id, item.Tint, item.TintAmt, item.Glow, item.GlowStr) }; Transform transform2 = val2.transform; transform2.localScale *= 0.6f; break; } case Kind.Notes: { GuideBook.SetupPrefab(val2, component, val3); val3.m_maxStackSize = 10; val3.m_weight = 0.5f; val3.m_icons = (Sprite[])(object)new Sprite[1] { GameArt.Recolor(BookArt.Icon(), item.Id, item.Tint, item.TintAmt, item.Glow, item.GlowStr) }; Transform transform = val2.transform; transform.localScale *= 0.75f; break; } case Kind.Potion: val3.m_consumeStatusEffect = null; val3.m_food = 0f; val3.m_foodStamina = 0f; val3.m_foodEitr = 0f; val3.m_maxStackSize = 10; break; case Kind.Scroll: val3.m_consumeStatusEffect = null; val3.m_food = 0f; val3.m_foodStamina = 0f; val3.m_foodEitr = 0f; val3.m_maxStackSize = 20; break; } component.m_itemData = component.m_itemData.Clone(); component.m_itemData.m_shared = val3; component.m_itemData.m_dropPrefab = val2; item.Prefab = val2; ByItemName[item.Name] = item; } } public static void RegisterObjectDB(ObjectDB db) { if ((Object)(object)db == (Object)null || db.m_items == null || db.m_items.Count == 0) { return; } try { FindTrinket(db.m_items); Build((string n) => db.GetItemPrefab(n)); bool flag = false; foreach (Def d in All) { if ((Object)(object)d.Prefab == (Object)null) { continue; } if (!db.m_items.Contains(d.Prefab)) { db.m_items.Add(d.Prefab); flag = true; } if (!db.m_recipes.Exists((Recipe r) => (Object)(object)r != (Object)null && ((Object)r).name == "Recipe_" + d.Id)) { Recipe val = MakeRecipe(db, d); if ((Object)(object)val != (Object)null) { db.m_recipes.Add(val); flag = true; } } } if (GaldrConfig.RemoveVanillaMagic.Value > 0.5f) { Staves.RegisterObjectDB(db); DisableVanillaMagic(db); } Blessings.RegisterObjectDB(db); foreach (Def item in All) { StatusEffect val2 = (((Object)(object)item.Prefab != (Object)null) ? item.Prefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_equipStatusEffect : null); if (item.Kind == Kind.Focus && (Object)(object)val2 != (Object)null && !db.m_StatusEffects.Contains(val2)) { db.m_StatusEffects.Add(val2); } } if ((Object)(object)ZNetScene.instance != (Object)null) { RegisterScene(ZNetScene.instance); } ArmorSets.Describe(db); if (flag) { MethodInfo methodInfo = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(db, null); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Galdr items (ObjectDB): " + ex)); } } private static void DisableVanillaMagic(ObjectDB db) { int num = 0; foreach (Recipe recipe in db.m_recipes) { if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && recipe.m_item.m_itemData != null && recipe.m_item.m_itemData.m_shared != null && Staves.IsVanillaMagic(recipe.m_item.m_itemData.m_shared) && recipe.m_enabled) { recipe.m_enabled = false; num++; } } if (num > 0) { Plugin.Log.LogInfo((object)("Game magic: recipes disabled: " + num)); } } public static void RegisterScene(ZNetScene zs) { if ((Object)(object)zs == (Object)null) { return; } try { FindTrinket(zs.m_prefabs); Build((string n) => zs.GetPrefab(n)); FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); Dictionary<int, GameObject> dictionary = ((fieldInfo != null) ? (fieldInfo.GetValue(zs) as Dictionary<int, GameObject>) : null); foreach (Def item in All) { if (!((Object)(object)item.Prefab == (Object)null)) { if (!zs.m_prefabs.Contains(item.Prefab)) { zs.m_prefabs.Add(item.Prefab); } if (dictionary != null) { dictionary[StringExtensionMethods.GetStableHashCode(item.Id)] = item.Prefab; } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Galdr items (scene): " + ex)); } } private static CraftingStation StationByName(ObjectDB db, string prefabName) { foreach (Recipe recipe in db.m_recipes) { if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_craftingStation != (Object)null && ((Object)recipe.m_craftingStation).name == prefabName) { return recipe.m_craftingStation; } } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabName) : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent<CraftingStation>(); } private static Recipe MakeRecipe(ObjectDB db, Def d) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown if (d.Res == null || d.Res.Length == 0) { return null; } CraftingStation val = StationByName(db, d.Station); List<Requirement> list = new List<Requirement>(); string[] res = d.Res; for (int i = 0; i < res.Length; i++) { string[] array = res[i].Split(new char[1] { ':' }); GameObject itemPrefab = db.GetItemPrefab(array[0]); ItemDrop val2 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("Galdr items: missing ingredient " + array[0] + " for «" + d.Name + "»")); return null; } list.Add(new Requirement { m_resItem = val2, m_amount = int.Parse(array[1]), m_amountPerLevel = ((array.Length > 2) ? int.Parse(array[2]) : 0), m_recover = (d.Kind == Kind.Charm) }); } Recipe obj = ScriptableObject.CreateInstance<Recipe>(); ((Object)obj).name = "Recipe_" + d.Id; obj.m_item = d.Prefab.GetComponent<ItemDrop>(); obj.m_amount = 1; obj.m_enabled = true; obj.m_craftingStation = val; obj.m_repairStation = val; obj.m_minStationLevel = d.StationLevel; obj.m_resources = list.ToArray(); return obj; } public static Def Of(ItemData item) { if (item == null || item.m_shared == null) { return null; } if ((Object)(object)item.m_dropPrefab != (Object)null) { string name = ((Object)item.m_dropPrefab).name; foreach (Def item2 in All) { if ((Object)(object)item2.Prefab != (Object)null && item2.Id == name) { return item2; } } } if (!ByItemName.TryGetValue(item.m_shared.m_name, out var value)) { return null; } return value; } public static void Sum(Player p, out float mana, out float regen) { mana = 0f; regen = 0f; if ((Object)(object)p == (Object)null) { return; } List<Food> foods = p.GetFoods(); if (foods == null) { return; } foreach (Food item in foods) { if (item != null) { Def def = Of(item.m_item); if (def != null && def.Kind == Kind.Food) { mana += def.Mana; regen += def.Regen; } } } } public static bool TryDrink(Player p, Inventory inv, ItemData item, out bool drunk) { drunk = false; Def def = Of(item); if (def == null || def.Kind != Kind.Potion) { return false; } MagicController instance = MagicController.Instance; if ((Object)(object)p != (Object)(object)Player.m_localPlayer || (Object)(object)instance == (Object)null || instance.Data == null) { return true; } if (Time.time < _potionReadyAt) { ((Character)p).Message((MessageType)2, Lang.F("manafoods.too_soon_n", Mathf.CeilToInt(_potionReadyAt - Time.time)), 0, (Sprite)null, false); return true; } _potionReadyAt = Time.time + 60f; instance.Mana = Mathf.Min(instance.MaxMana(), instance.Mana + def.Mana); if (inv != null) { inv.RemoveOneItem(item); } drunk = true; return true; } private static void OnChestFilled(Container __instance) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Invalid comparison between Unknown and I4 //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Invalid comparison between Unknown and I4 //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Invalid comparison between Unknown and I4 //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Invalid comparison between Unknown and I4 //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Invalid comparison between Unknown and I4 //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Invalid comparison between Unknown and I4 try { if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).GetComponent<TombStone>() != (Object)null) { return; } Piece component = ((Component)__instance).GetComponent<Piece>(); if ((Object)(object)component != (Object)null && component.GetCreator() != 0L) { return; } if (((Component)__instance).transform.position.y > 3000f && Random.value < GaldrConfig.TrickChance.Value) { List<Def> list = All.FindAll((Def x) => x.Kind == Kind.Trick && (Object)(object)x.Prefab != (Object)null); if (list.Count > 0) { __instance.GetInventory().AddItem(list[Random.Range(0, list.Count)].Prefab, 1); } } if (Random.value > GaldrConfig.NotesChance.Value) { return; } int num = 1; if (WorldGenerator.instance != null) { Biome biome = WorldGenerator.instance.GetBiome(((Component)__instance).transform.position); if ((int)biome == 2 || (int)biome == 4) { num = 2; } else if ((int)biome == 16 || (int)biome == 512 || (int)biome == 32 || (int)biome == 64) { num = 3; } } Def def = null; foreach (Def item in All) { if (item.Kind == Kind.Notes && item.Id == "GaldrNotes" + num) { def = item; } } if (def != null && !((Object)(object)def.Prefab == (Object)null)) { __instance.GetInventory().AddItem(def.Prefab, 1); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Notes in chest: " + ex.Message)); } } public static int CharmLevel(Player p) { if ((Object)(object)p == (Object)null) { return 0; } Inventory inventory = ((Humanoid)p).GetInventory(); if (inventory == null) { return 0; } foreach (ItemData equippedItem in inventory.GetEquippedItems()) { Def def = Of(equippedItem); if (def != null && def.Kind == Kind.Charm) { return Mathf.Max(1, equippedItem.m_quality); } } return 0; } public static bool TryRead(Player p, Inventory inv, ItemData item) { Def def = Of(item); if (def == null || (def.Kind != Kind.Scroll && def.Kind != Kind.Notes && def.Kind != Kind.Trick)) { return false; } if ((Object)(object)p != (Object)(object)Player.m_localPlayer || (Object)(object)MagicController.Instance == (Object)null || MagicController.Instance.Data == null) { return true; } if (def.Kind == Kind.Trick) { Tricks.Def def2 = Tricks.ById(def.Trick); if (def2 == null) { return true; } if (!Tricks.Learn(def2.Id)) { ((Character)p).Message((MessageType)2, Lang.T("manafoods.you_already_know_this_technique"), 0, (Sprite)null, false); return true; } ((Character)p).Message((MessageType)2, Lang.F("manafoods.technique_learned_n", def2.Name), 0, (Sprite)null, false); if (inv != null) { inv.RemoveOneItem(item); } return true; } Rewards.Add(def.Knowledge, def.Name.ToLowerInvariant()); if (inv != null) { inv.RemoveOneItem(item); } return true; } } [Serializable] public class SpellState { public string id; public bool unlocked; public int[] ranks = new int[3]; public string name = ""; public List<string> forms = new List<string>(); public List<string> formsEn = new List<string>(); public Dictionary<string, List<string>> formsBy = new Dictionary<string, List<string>>(); public Dictionary<string, string> nameBy = new Dictionary<string, string>(); private static readonly List<string> Empty = new List<string>(); public int TotalRanks => ranks[0] + ranks[1] + ranks[2]; public string Word { get { if (nameBy != null && VoiceLang.Current != null && nameBy.TryGetValue(VoiceLang.Current, out var value) && !string.IsNullOrEmpty(value)) { return value; } List<string> list = Forms; if (list != null && list.Count > 0) { return list[0]; } return name ?? ""; } } public bool AnyWord { get { if (!HasWord) { return HasOtherWord; } return true; } } public List<string> Forms => FormsFor(VoiceLang.Current); public bool HasWord { get { List<string> list = Forms; if (list != null) { return list.Count > 0; } return false; } } public bool HasOtherWord { get { string current = VoiceLang.Current; if (current != "ru" && forms.Count > 0) { return true; } if (current != "en" && formsEn.Count > 0) { return true; } foreach (KeyValuePair<string, List<string>> item in formsBy) { if (item.Key != current && item.Value != null && item.Value.Count > 0) { return true; } } return false; } } public List<string> FormsFor(string code) { switch (code) { case "ru": return forms; case "en": return formsEn; default: { if (formsBy.TryGetValue(code, out var value)) { return value; } break; } case null: break; } return Empty; } public void SetFormsFor(string code, List<string> f) { switch (code) { case "ru": forms = f; break; case "en": formsEn = f; break; default: formsBy[code] = f; break; case null: break; } } public void SetWord(string code, string word) { if (nameBy == null) { nameBy = new Dictionary<string, string>(); } if (code != null) { nameBy[code] = word ?? ""; } name = word ?? ""; } public void SetForms(List<string> f) { SetFormsFor(VoiceLang.Current, f); } } [Serializable] public class PlayerMagicData { public int version = 1; public long savedAt; public int native = -1; public float knowledge; public float healProgress; public List<SpellState> spells = new List<SpellState>(); public int[] core = new int[3]; public List<string> stones = new List<string>(); public List<int> bosses = new List<int>(); public List<string> trophies = new List<string>(); public List<string> tricks = new List<string>(); public int bookPages; public List<string> loadout = new List<string>(); public bool loadoutSet; public string passive = ""; public int preset; public List<string>[] presets = new List<string>[3] { new List<string>(), new List<string>(), new List<string>() }; public bool[] presetSet = new bool[3]; public Dictionary<string, int> casts = new Dictionary<string, int>(); public int kills; public int shouts; public int whispers; public int misfires; public int quick; public float manaSpent; public float bestHit; public string bestHitSpell = ""; public long firstCast; public SpellState Get(string id, bool create) { for (int i = 0; i < spells.Count; i++) { if (spells[i].id == id) { return spells[i]; } } if (!create) { return null; } SpellState spellState = new SpellState { id = id }; spells.Add(spellState); return spellState; } public void Sanitize() { if (spells == null) { spells = new List<SpellState>(); } if (core == null || core.Length != 3) { core = new int[3]; } if (stones == null) { stones = new List<string>(); } if (bosses == null) { bosses = new List<int>(); } if (trophies == null) { trophies = new List<string>(); } if (tricks == null) { tricks = new List<string>(); } if (loadout == null) { loadout = new List<string>(); } loadout.RemoveAll((string id) => SpellDefs.Get(id) == null || SpellDefs.Get(id).Tier == 0); if (presets == null || presets.Length != 3) { presets = new List<string>[3] { new List<string>(), new List<string>(), new List<string>() }; } for (int num = 0; num < 3; num++) { if (presets[num] == null) { presets[num] = new List<string>(); } presets[num].RemoveAll((string id) => SpellDefs.Get(id) == null || SpellDefs.Get(id).Tier == 0); } if (presetSet == null || presetSet.Length != 3) { presetSet = new bool[3]; } preset = Mathf.Clamp(preset, 0, 2); if (casts == null) { casts = new Dictionary<string, int>(); } if (bestHitSpell == null) { bestHitSpell = ""; } if (passive == null) { passive = ""; } foreach (SpellState spell in spells) { if (spell.ranks == null || spell.ranks.Length != 3) { spell.ranks = new int[3]; } if (spell.forms == null) { spell.forms = new List<string>(); } if (spell.formsEn == null) { spell.formsEn = new List<string>(); } if (spell.formsBy == null) { spell.formsBy = new Dictionary<string, List<string>>(); } if (spell.name == null) { spell.name = ""; } if (spell.nameBy == null) { spell.nameBy = new Dictionary<string, string>(); } } } public string Summary() { int num = 0; foreach (SpellState spell in spells) { if (spell.unlocked) { num++; } } string text = ((native >= 0) ? SpellDefs.ElementName((Element)native) : "not chosen"); int num2 = 0; foreach (SpellState spell2 in spells) { if (spell2.HasWord) { num2++; } } return "element " + text + ", Knowledge " + Mathf.FloorToInt(knowledge) + ", spells unlocked " + num + ", words " + num2; } } public static class Persistence { private const string Key = "Galdr_Data"; private static readonly FieldInfo CustomDataField = AccessTools.Field(typeof(Player), "m_customData"); private static string _currentPath; private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; private static bool _loggedSave; private static Dictionary<string, string> Dict(Player p) { if (CustomDataField == null || (Object)(object)p == (Object)null) { return null; } return CustomDataField.GetValue(p) as Dictionary<string, string>; } private static string FilePath(string playerName) { string text = Path.Combine(Paths.ConfigPath, "Galdr"); Directory.CreateDirectory(text); string text2 = (string.IsNullOrEmpty(playerName) ? "unnamed" : playerName); char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { text2 = text2.Replace(oldChar, '_'); } return Path.Combine(text, text2 + ".txt"); } private static PlayerMagicData Parse(string text, string source) { if (string.IsNullOrEmpty(text)) { return null; } try { PlayerMagicData playerMagicData = (text.TrimStart(Array.Empty<char>()).StartsWith("{") ? JsonUtility.FromJson<PlayerMagicData>(text) : Deserialize(text)); playerMagicData?.Sanitize(); return playerMagicData; } catch (Exception ex) { Plugin.Log.LogError((object)("Corrupted magic data (" + source + "): " + ex.Message)); return null; } } private static string B64(string s) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(s ?? "")); } private static string UnB64(string s) { if (string.IsNullOrEmpty(s)) { return ""; } try { return Encoding.UTF8.GetString(Convert.FromBase64String(s)); } catch { return ""; } } private static string Join(IEnumerable<int> xs) { StringBuilder stringBuilder = new StringBuilder(); foreach (int x in xs) { if (stringBuilder.Length > 0) { stringBuilder.Append(','); } stringBuilder.Append(x.ToString(Inv)); } return stringBuilder.ToString(); } private static List<int> Ints(string s) { List<int> list = new List<int>(); if (string.IsNullOrEmpty(s)) { return list; } string[] array = s.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { if (int.TryParse(array[i], NumberStyles.Integer, Inv, out var result)) { list.Add(result); } } return list; } public static string Serialize(PlayerMagicData d) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("galdr=2\n"); stringBuilder.Append("savedAt=").Append(d.savedAt.ToString(Inv)).Append('\n'); stringBuilder.Append("native=").Append(d.native.ToString(Inv)).Append('\n'); stringBuilder.Append("knowledge=").Append(d.knowledge.ToString("R", Inv)).Append('\n'); stringBuilder.Append("heal=").Append(d.healProgress.ToString("R", Inv)).Append('\n'); stringBuilder.Append("core=").Append(Join(d.core)).Append('\n'); stringBuilder.Append("bosses=").Append(Join(d.bosses)).Append('\n'); List<string> list = new List<string>(); foreach (string stone in d.stones) { list.Add(B64(stone)); } stringBuilder.Append("trophies=").Append(string.Join(",", d.trophies.ToArray())).Append('\n'); stringBuilder.Append("pages=").Append(d.bookPages.ToString(Inv)).Append('\n'); stringBuilder.Append("tricks=").Append(string.Join(",", d.tricks.ToArray())).Append('\n'); stringBuilder.Append("stones=").Append(string.Join(",", list.ToArray())).Append('\n'); if (d.loadoutSet) { stringBuilder.Append("loadout=").Append(string.Join(",", d.loadout.ToArray())).Append('\n'); } stringBuilder.Append("preset=").Append(d.preset.ToString(Inv)).Append('\n'); if (!string.IsNullOrEmpty(d.passive)) { stringBuilder.Append("passive=").Append(d.passive).Append('\n'); } for (int i = 0; i < 3; i++) { if (d.presetSet[i] && i != d.preset) { stringBuilder.Append("preset").Append(i.ToString(Inv)).Append('=') .Append(string.Join(",", d.presets[i].ToArray())) .Append('\n'); } } if (d.casts.Count > 0) { List<string> list2 = new List<string>(); foreach (KeyValuePair<string, int> cast in d.casts) { list2.Add(cast.Key + ":" + cast.Value.ToString(Inv)); } stringBuilder.Append("casts=").Append(string.Join(",", list2.ToArray())).Append('\n'); } stringBuilder.Append("chron=").Append(Join(new int[5] { d.kills, d.shouts, d.whispers, d.misfires, d.quick })).Append('|') .Append(d.manaSpent.ToString("R", Inv)) .Append('|') .Append(d.firstCast.ToString(Inv)) .Append('|') .Append(d.bestHit.ToString("R", Inv)) .Append('|') .Append(d.bestHitSpell ?? "") .Append('\n'); foreach (SpellState spell in d.spells) { List<string> list3 = new List<string>(); foreach (string form in spell.forms) { list3.Add(B64(form)); } List<string> list4 = new List<string>(); if (spell.formsEn != null) { foreach (string item in spell.formsEn) { list4.Add(B64(item)); } } stringBuilder.Append("spell=").Append(spell.id).Append('|') .Append(spell.unlocked ? '1' : '0') .Append('|') .Append(Join(spell.ranks)) .Append('|') .Append(B64(spell.name)) .Append('|') .Append(string.Join(",", list3.ToArray())) .Append('|') .Append(string.Join(",", list4.ToArray())) .Append('\n'); if (spell.formsBy != null) { foreach (KeyValuePair<string, List<string>> item2 in spell.formsBy) { if (item2.Value == null || item2.Value.Count == 0) { continue; } List<string> list5 = new List<string>(); foreach (string item3 in item2.Value) { list5.Add(B64(item3)); } stringBuilder.Append("words=").Append(spell.id).Append('|') .Append(item2.Key) .Append('|') .Append(string.Join(",", list5.ToArray())) .Append('\n'); } } if (spell.nameBy == null) { continue; } foreach (KeyValuePair<string, string> item4 in spell.nameBy) { if (!string.IsNullOrEmpty(item4.Value)) { stringBuilder.Append("word=").Append(spell.id).Append('|') .Append(item4.Key) .Append('|') .Append(B64(item4.Value)) .Append('\n'); } } } return stringBuilder.ToString(); } public static PlayerMagicData Deserialize(string text) { PlayerMagicData playerMagicData = new PlayerMagicData(); string[] array = text.Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim('\r', ' '); int num = text2.IndexOf('='); if (num <= 0) { continue; } string text3 = text2.Substring(0, num); string text4 = text2.Substring(num + 1); switch (text3) { case "savedAt": long.TryParse(text4, NumberStyles.Integer, Inv, out playerMagicData.savedAt); break; case "native": int.TryParse(text4, NumberStyles.Integer, Inv, out playerMagicData.native); break; case "knowledge": float.TryParse(text4, NumberStyles.Float, Inv, out playerMagicData.knowledge); break; case "heal": float.TryParse(text4, NumberStyles.Float, Inv, out playerMagicData.healProgress); break; case "core": { List<int> list2 = Ints(text4); for (int l = 0; l < 3 && l < list2.Count; l++) { playerMagicData.core[l] = list2[l]; } break; } case "bosses": playerMagicData.bosses = Ints(text4); break; case "trophies": playerMagicData.trophies = new List<string>(text4.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)); break; case "pages": int.TryParse(text4, NumberStyles.Integer, Inv, out playerMagicData.bookPages); break; case "tricks": playerMagicData.tricks = new List<string>(text4.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)); break; case "stones": playerMagicData.stones = new List<string>(); if (text4.Length > 0) { string[] array3 = text4.Split(new char[1] { ',' }); foreach (string s in array3) { playerMagicData.stones.Add(UnB64(s)); } } break; case "loadout": playerMagicData.loadout = new List<string>(text4.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)); playerMagicData.loadoutSet = true; break; case "passive": playerMagicData.passive = text4.Trim(); break; case "preset": int.TryParse(text4, NumberStyles.Integer, Inv, out playerMagicData.preset); playerMagicData.preset = Mathf.Clamp(playerMagicData.preset, 0, 2); break; case "preset0": case "preset1": case "preset2": { int num3 = text3[6] - 48; playerMagicData.presets[num3] = new List<string>(text4.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)); playerMagicData.presetSet[num3] = true; break; } case "casts": { string[] array3 = text4.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text7 in array3) { int num2 = text7.LastIndexOf(':'); if (num2 > 0 && int.TryParse(text7.Substring(num2 + 1), NumberStyles.Integer, Inv, out var result)) { playerMagicData.casts[text7.Substring(0, num2)] = result; } } break; } case "chron": { string[] array4 = text4.Split(new char[1] { '|' }); List<int> list3 = Ints(array4[0]); if (list3.Count > 0) { playerMagicData.kills = list3[0]; } if (list3.Count > 1) { playerMagicData.shouts = list3[1]; } if (list3.Count > 2) { playerMagicData.whispers = list3[2]; } if (list3.Count > 3) { playerMagicData.misfires = list3[3]; } if (list3.Count > 4) { playerMagicData.quick = list3[4]; } if (array4.Length > 1) { float.TryParse(array4[1], NumberStyles.Float, Inv, out playerMagicData.manaSpent); } if (array4.Length > 2) { long.TryParse(array4[2], NumberStyles.Integer, Inv, out playerMagicData.firstCast); } if (array4.Length > 3) { float.TryParse(array4[3], NumberStyles.Float, Inv, out playerMagicData.bestHit); } if (array4.Length > 4) { playerMagicData.bestHitSpell = array4[4]; } break; } case "word": { string[] array6 = text4.Split(new char[1] { '|' }); if (array6.Length >= 3 && SpellDefs.Get(array6[0]) != null) { SpellState spellState3 = playerMagicData.Get(array6[0], create: true); if (spellState3.nameBy == null) { spellState3.nameBy = new Dictionary<string, string>(); } spellState3.nameBy[array6[1]] = UnB64(array6[2]); } break; } case "words": { string[] array5 = text4.Split(new char[1] { '|' }); if (array5.Length < 3 || SpellDefs.Get(array5[0]) == null) { break; } SpellState spellState2 = playerMagicData.Get(array5[0], create: true); List<string> list4 = new List<string>(); if (array5[2].Length > 0) { string[] array3 = array5[2].Split(new char[1] { ',' }); for (int k = 0; k < array3.Length; k++) { string text8 = UnB64(array3[k]); if (text8.Length > 0) { list4.Add(text8); } } } spellState2.SetFormsFor(array5[1], list4); break; } case "spell": { string[] array2 = text4.Split(new char[1] { '|' }); if (array2.Length < 5 || SpellDefs.Get(array2[0]) == null) { break; } SpellState spellState = playerMagicData.Get(array2[0], create: true); spellState.unlocked = array2[1] == "1"; List<int> list = Ints(array2[2]); for (int j = 0; j < 3 && j < list.Count; j++) { spellState.ranks[j] = list[j]; } spellState.name = UnB64(array2[3]); spellState.forms = new List<string>(); string[] array3; if (array2[4].Length > 0) { array3 = array2[4].Split(new char[1] { ',' }); for (int k = 0; k < array3.Length; k++) { string text5 = UnB64(array3[k]); if (text5.Length > 0) { spellState.forms.Add(text5); } } } spellState.formsEn = new List<string>(); if (array2.Length <= 5 || array2[5].Length <= 0) { break; } array3 = array2[5].Split(new char[1] { ',' }); for (int k = 0; k < array3.Length; k++) { string text6 = UnB64(array3[k]); if (text6.Length > 0) { spellState.formsEn.Add(text6); } } break; } } } return playerMagicData; } public static PlayerMagicData Load(Player p, string playerName) { PlayerMagicData playerMagicData = null; PlayerMagicData playerMagicData2 = null; string text = null; try { text = (_currentPath = FilePath(playerName)); if (File.Exists(text)) { playerMagicData = Parse(File.ReadAllText(text), "file"); } } catch (Exception ex) { Plugin.Log.LogError((object)("Couldn't read the progress file: " + ex.Message)); } try { Dictionary<string, string> dictionary = Dict(p); if (dictionary != null && dictionary.TryGetValue("Galdr_Data", out var value)) { playerMagicData2 = Parse(value, "character"); } } catch (Exception ex2) { Plugin.Log.LogError((object)("Couldn't read progress from the character: " + ex2.Message)); } PlayerMagicData playerMagicData3 = playerMagicData; string text2 = "file"; if (playerMagicData2 != null && (playerMagicData3 == null || playerMagicData2.s