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 Rist v1.7.0
plugins/Rist/Rist.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Ezomic.Core; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Sprites; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("Thijssen Software")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 Robbin Thijssen")] [assembly: AssemblyDescription("A character level beside the skills, paid out in cards you draft and deepen.")] [assembly: AssemblyFileVersion("1.7.0.0")] [assembly: AssemblyInformationalVersion("1.7.0+87775339d5d1602a2e7387c6a68ddb37f4dd31b5")] [assembly: AssemblyProduct("Rist")] [assembly: AssemblyTitle("Rist")] [assembly: AssemblyVersion("1.7.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Rist { internal static class AnsweringBlow { internal static class Arm { private const float EnemyRange = 8f; [HarmonyPatch(typeof(Player), "RPC_HitWhileDodging")] [HarmonyPrefix] private static void Before(Player __instance, out bool __state) { __state = RistConfig.Enabled.Value && __instance == Player.m_localPlayer && Bind() && !_beenHit.Invoke(__instance); } [HarmonyPatch(typeof(Player), "RPC_HitWhileDodging")] [HarmonyPostfix] private static void After(Player __instance, bool __state) { if (__state && _beenHit.Invoke(__instance) && !(Time.time <= _armedUntil) && !(Effects.TotalFor("*answer") <= 0f) && EnemyNear(__instance)) { _armedUntil = Time.time + 4f; ((Character)__instance).Message((MessageType)1, "Answering blow ready", 0, (Sprite)null, false); } } private static bool EnemyNear(Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)player).transform.position; foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsDead() && (object)allCharacter != player && BaseAI.IsEnemy((Character)(object)player, allCharacter) && Vector3.Distance(position, ((Component)allCharacter).transform.position) <= 8f) { return true; } } return false; } } internal static class Spend { [HarmonyPatch(typeof(Character), "Damage")] [HarmonyPrefix] private static void Damaging(Character __instance, HitData hit) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 if (_armedUntil < 0f || hit == null || (Object)(object)__instance == (Object)null) { return; } if (Time.time > _armedUntil) { _armedUntil = -1f; return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && (object)hit.GetAttacker() == localPlayer && (int)hit.m_hitType == 2 && BaseAI.IsEnemy((Character)(object)localPlayer, __instance)) { _armedUntil = -1f; float num = Effects.TotalFor("*answer"); if (num > 0f) { ((DamageTypes)(ref hit.m_damage)).Modify(1f + num); } float num2 = Mathf.Clamp01(Effects.TotalFor("*answer:stagger")); if (num2 > 0f && __instance.m_staggerWhenBlocked && !Bosses.Is(__instance) && Random.value < num2) { hit.m_staggerMultiplier = Mathf.Max(hit.m_staggerMultiplier, 100f); } } } } internal const string Bonus = "*answer"; internal const string Stagger = "*answer:stagger"; private const float Window = 4f; private static float _armedUntil = -1f; private static FieldRef<Player, bool> _beenHit; private static bool _bound; private static bool _bindFailed; private static bool Bind() { if (_bound) { return true; } if (_bindFailed) { return false; } try { _beenHit = AccessTools.FieldRefAccess<Player, bool>("m_beenHitWhileDodging"); _bound = true; } catch (Exception ex) { _bindFailed = true; RistPlugin.Log.LogError((object)("Answering blow could not reach the game's dodge field and is off for this session: " + ex.Message)); } return _bound; } } internal static class Bosses { internal static bool Is(Character c) { if ((Object)(object)c == (Object)null) { return false; } if (c.IsBoss()) { return true; } string defeatSetGlobalKey = c.m_defeatSetGlobalKey; if (string.IsNullOrEmpty(defeatSetGlobalKey)) { return false; } try { Enum.Parse(typeof(GlobalKeys), defeatSetGlobalKey, ignoreCase: true); return false; } catch { return true; } } } internal static class AttackSpeed { internal static class Reload { [HarmonyPatch(typeof(ItemData), "GetWeaponLoadingTime")] [HarmonyPostfix] private static void Loading(ItemData __instance, ref float __result) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 if (RistConfig.Enabled.Value && !(__result <= 0f) && __instance != null && __instance.m_shared != null && __instance.m_shared.m_attack.m_requiresReload && (int)__instance.m_shared.m_skillType == 14) { float num = Mathf.Min(Effects.TotalFor("*attackspeed:ranged"), Mathf.Max(0f, RistConfig.AttackSpeedMax.Value)); if (!(num <= 0f)) { __result /= 1f + num; } } } } internal static class Unbroken { private static Attack _fired; private static FieldRef<Attack, Humanoid> _attackCharacter; private static FieldRef<Attack, ItemData> _attackWeapon; private static FieldRef<Humanoid, Attack> _currentAttack; private static FieldRef<Attack, int> _burstsFired; private static bool _bound; private static bool _bindFailed; private static bool Bind() { if (_bound) { return true; } if (_bindFailed) { return false; } try { _attackCharacter = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character"); _attackWeapon = AccessTools.FieldRefAccess<Attack, ItemData>("m_weapon"); _currentAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_currentAttack"); _burstsFired = AccessTools.FieldRefAccess<Attack, int>("m_projectileBurstsFired"); _bound = true; } catch (Exception ex) { _bindFailed = true; RistPlugin.Log.LogError((object)("Quick chant's capstone could not reach the game's attack fields and is off for this session: " + ex.Message)); } return _bound; } [HarmonyPatch(typeof(Attack), "OnAttackTrigger")] [HarmonyPrefix] private static void Fired(Attack __instance) { if (Bind() && (object)_attackCharacter.Invoke(__instance) == Player.m_localPlayer) { _fired = __instance; } } [HarmonyPatch(typeof(Character), "RPC_Stagger")] [HarmonyPrefix] private static bool Staggering(Character __instance) { if (!RistConfig.Enabled.Value) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (object)__instance != localPlayer) { return true; } if (!((Character)localPlayer).InAttack() || !Bind()) { return true; } Attack val = _currentAttack.Invoke((Humanoid)(object)localPlayer); if (val == null) { return true; } ItemData val2 = _attackWeapon.Invoke(val); if (val2 == null || val2.m_shared == null || CategoryOf(val2) != "*attackspeed:magic") { return true; } if (val == _fired && (val.m_loopingAttack || val.m_projectileBursts <= 1 || _burstsFired.Invoke(val) >= val.m_projectileBursts)) { return true; } return Effects.TotalFor("*unbroken") <= 0f; } } internal static class BowDraw { private static int _frame = -1; private static float _bonus; [HarmonyPatch(typeof(Humanoid), "GetAttackDrawPercentage")] [HarmonyPostfix] private static void Drawn(Humanoid __instance, ref float __result) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 if (__result <= 0f || __result >= 1f || !RistConfig.Enabled.Value || (object)__instance != Player.m_localPlayer) { return; } ItemData currentWeapon = __instance.GetCurrentWeapon(); if (currentWeapon != null && currentWeapon.m_shared != null && (int)currentWeapon.m_shared.m_skillType == 8) { if (_frame != Time.frameCount) { _frame = Time.frameCount; _bonus = Mathf.Min(Effects.TotalFor("*attackspeed:ranged"), Mathf.Max(0f, RistConfig.AttackSpeedMax.Value)); } if (!(_bonus <= 0f)) { __result = Mathf.Clamp01(__result * (1f + _bonus)); } } } } internal const string Melee = "*attackspeed:melee"; internal const string Tools = "*attackspeed:tools"; internal const string Ranged = "*attackspeed:ranged"; internal const string Magic = "*attackspeed:magic"; internal const string UnbrokenCast = "*unbroken"; private static string CategoryOf(ItemData weapon) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected I4, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Invalid comparison between Unknown and I4 if (weapon == null || weapon.m_shared == null) { return null; } SkillType skillType = weapon.m_shared.m_skillType; switch (skillType - 1) { case 7: case 13: return "*attackspeed:ranged"; case 8: case 9: return "*attackspeed:magic"; case 6: case 11: case 12: return "*attackspeed:tools"; case 0: case 1: case 2: case 3: case 4: case 10: return "*attackspeed:melee"; default: if ((int)weapon.m_shared.m_itemType != 19) { return null; } return "*attackspeed:tools"; } } [HarmonyPatch(typeof(Attack), "Start")] [HarmonyPostfix] private static void Started(Attack __instance, bool __result, Humanoid character, CharacterAnimEvent animEvent, ItemData weapon) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Invalid comparison between Unknown and I4 if (!__result || !RistConfig.Enabled.Value || (Object)(object)character == (Object)null || (Object)(object)animEvent == (Object)null || (object)character != Player.m_localPlayer) { return; } string text = CategoryOf(weapon); if (text == null) { return; } float num = Effects.TotalFor(text); if (num <= 0f) { return; } num = Mathf.Min(num, Mathf.Max(0f, RistConfig.AttackSpeedMax.Value)); if (text == "*attackspeed:magic") { if (__instance.m_loopingAttack && ((int)__instance.m_attackType != 2 || !__instance.m_perBurstResourceUsage)) { return; } if (__instance.m_projectileBursts > 1) { __instance.m_burstInterval /= 1f + num; } } animEvent.Speed(1f + num); } } internal sealed class Card { internal string Id; internal string Name; internal string Flavour; internal string Effect; internal float PerRank; internal string BonusEffect = ""; internal float BonusPerRank; internal string Sigil = ""; internal string Aett = ""; internal FieldInfo Field; internal FieldInfo BonusField; private static readonly HashSet<string> ShownAsReduction = new HashSet<string> { "*windcone" }; private static HashSet<string> _oneBased; private static readonly HashSet<string> Fallback = new HashSet<string> { "m_healthRegenMultiplier", "m_staminaRegenMultiplier", "m_eitrRegenMultiplier", "m_damageModifier" }; private static readonly HashSet<string> DeadFields = new HashSet<string> { "m_runStaminaUseModifier" }; private static readonly HashSet<string> LowerIsBetter = new HashSet<string> { "m_runStaminaDrainModifier", "m_attackStaminaUseModifier", "m_blockStaminaUseModifier", "m_swimStaminaUseModifier", "m_jumpStaminaUseModifier", "m_sneakStaminaUseModifier", "m_dodgeStaminaUseModifier", "*stamina:move", "*stamina:fight", "m_fallDamageModifier", "m_stealthModifier", "m_noiseModifier", "m_staggerModifier", "*power:cooldown", "*overloaded" }; private static readonly Dictionary<string, string> Labels = new Dictionary<string, string> { { "m_addMaxCarryWeight", "carry weight" }, { "m_addArmor", "armour" }, { "m_armorMultiplier", "armour" }, { "*inventoryrow", "inventory row" }, { "*exploreradius", "map sight" }, { "*windcone", "dead zone" }, { "*rowspeed", "rowing speed" }, { "m_runStaminaUseModifier", "run stamina" }, { "m_runStaminaDrainModifier", "run stamina drain" }, { "m_attackStaminaUseModifier", "attack stamina" }, { "m_blockStaminaUseModifier", "block stamina" }, { "m_swimStaminaUseModifier", "swim stamina" }, { "m_jumpStaminaUseModifier", "jump stamina" }, { "m_sneakStaminaUseModifier", "sneak stamina" }, { "m_staminaRegenMultiplier", "stamina regen" }, { "m_healthRegenMultiplier", "health regen" }, { "m_eitrRegenMultiplier", "eitr regen" }, { "m_fallDamageModifier", "fall damage" }, { "m_stealthModifier", "detection" }, { "m_noiseModifier", "noise" }, { "m_staggerModifier", "stagger taken" }, { "m_raiseSkillModifier", "skill gain" }, { "m_skillLevelModifier", "skill levels" }, { "m_speedModifier", "movement speed" }, { "m_damageModifier", "damage" }, { "m_dodgeStaminaUseModifier", "dodge stamina" }, { "m_swimSpeedModifier", "swim speed" }, { "m_timedBlockBonus", "parry bonus" }, { "*stamina:move", "move stamina" }, { "*stamina:fight", "combat stamina" }, { "*attackspeed:melee", "melee speed" }, { "*attackspeed:tools", "tool speed" }, { "*attackspeed:ranged", "draw and reload" }, { "*attackspeed:magic", "cast speed" }, { "*unbroken", "a hit cannot break a cast" }, { "*damage:ranged", "bow and crossbow damage" }, { "*answer", "answering blow" }, { "*answer:stagger", "chance the answering blow staggers" }, { "*lowdraw", "s unseen draw" }, { "*lowdraw:silent", "arrows from a crouch land silent" }, { "*sneakattack", "sneak attack" }, { "*sneakattack:stagger", "an ambush staggers" }, { "*mead:duration", "mead duration" }, { "*mead:fullcask", "chance a mead is not used up" }, { "*power:cooldown", "power cooldown" }, { "*power:duration", "s of forsaken power" }, { "*staminadelay", "s less before stamina returns" }, { "*jumpheight", "jump height" }, { "*overloaded", "stamina walking overloaded" } }; private static readonly HashSet<string> Percent = new HashSet<string> { "m_runStaminaUseModifier", "m_attackStaminaUseModifier", "m_blockStaminaUseModifier", "m_swimStaminaUseModifier", "m_jumpStaminaUseModifier", "m_sneakStaminaUseModifier", "m_staminaRegenMultiplier", "m_healthRegenMultiplier", "m_eitrRegenMultiplier", "m_fallDamageModifier", "m_stealthModifier", "m_noiseModifier", "m_staggerModifier", "m_raiseSkillModifier", "m_speedModifier", "m_damageModifier", "m_dodgeStaminaUseModifier", "m_swimSpeedModifier", "m_timedBlockBonus", "m_armorMultiplier", "*attackspeed:melee", "*attackspeed:tools", "*attackspeed:ranged", "*attackspeed:magic", "*damage:ranged", "*answer", "*answer:stagger", "*sneakattack", "*mead:duration", "*mead:fullcask", "*power:cooldown", "*stamina:move", "*stamina:fight", "m_runStaminaDrainModifier", "*exploreradius", "*windcone", "*rowspeed", "*jumpheight", "*overloaded" }; internal static readonly HashSet<string> Specials = new HashSet<string> { "*inventoryrow", "*attackspeed:melee", "*attackspeed:tools", "*attackspeed:ranged", "*attackspeed:magic", "*unbroken", "*damage:ranged", "*answer", "*answer:stagger", "*lowdraw", "*lowdraw:silent", "*sneakattack", "*sneakattack:stagger", "*mead:duration", "*mead:fullcask", "*power:cooldown", "*power:duration", "*exploreradius", "*windcone", "*rowspeed", "*staminadelay", "*jumpheight", "*overloaded", "*stamina:move", "*stamina:fight" }; private static readonly HashSet<string> Unlocks = new HashSet<string> { "*unbroken", "*lowdraw:silent", "*sneakattack:stagger" }; private static readonly HashSet<string> Seconds = new HashSet<string> { "*lowdraw", "*power:duration", "*staminadelay" }; internal bool IsSpecial => IsSpecialEffect(Effect); internal bool HasBonus => BonusEffect.Length > 0; internal static bool IsSpecialEffect(string effect) { if (effect != null && effect.Length > 0) { return effect[0] == '*'; } return false; } internal static int BonusTimes(int rank) { int num = Mathf.Max(1, RistConfig.BonusEvery.Value); return rank / num; } internal string Describe(int rank) { return Format(Effect, PerRank * (float)Mathf.Max(1, rank)); } internal string DescribeBonus(int times) { return Format(BonusEffect, BonusPerRank * (float)Mathf.Max(1, times)); } private static string Format(string effect, float total) { if (!Labels.TryGetValue(effect, out var value)) { value = effect; } if (Unlocks.Contains(effect)) { return value; } if (ShownAsReduction.Contains(effect)) { total = 0f - total; } if (Percent.Contains(effect)) { float num = total * 100f; return ((num >= 0f) ? "+" : "−") + Mathf.Abs(num).ToString("0.#", CultureInfo.InvariantCulture) + "% " + value; } return ((total >= 0f) ? "+" : "−") + Mathf.Abs(total).ToString("0.#", CultureInfo.InvariantCulture) + " " + value; } internal static bool IsOneBased(string effect) { return Neutrals().Contains(effect); } private static HashSet<string> Neutrals() { if (_oneBased != null) { return _oneBased; } try { SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); if ((Object)(object)val == (Object)null) { _oneBased = Fallback; return _oneBased; } HashSet<string> hashSet = new HashSet<string>(); FieldInfo[] fields = typeof(SE_Stats).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType != typeof(float)) && Mathf.Approximately((float)fieldInfo.GetValue(val), 1f)) { hashSet.Add(fieldInfo.Name); } } Object.Destroy((Object)(object)val); foreach (string item in Fallback) { if (!hashSet.Contains(item)) { RistPlugin.Log.LogWarning((object)("SE_Stats." + item + " no longer defaults to 1, so Rist has stopped treating it as a multiplier. Check the cards that target it - the game has changed what neutral means.")); } } foreach (string item2 in hashSet) { if (!Fallback.Contains(item2)) { RistPlugin.Log.LogInfo((object)("SE_Stats." + item2 + " defaults to 1 and is being treated as a multiplier; it was not one when Rist was written.")); } } _oneBased = hashSet; } catch (Exception ex) { RistPlugin.Log.LogWarning((object)("Could not read SE_Stats' neutral values, so Rist is using the four multipliers it was written against. " + ex.Message)); _oneBased = Fallback; } return _oneBased; } internal static bool HasLabel(string effect) { if (!string.IsNullOrEmpty(effect)) { return Labels.ContainsKey(effect); } return false; } internal static bool ReadsAsRawFraction(string effect, float value) { if (string.IsNullOrEmpty(effect) || Percent.Contains(effect) || Seconds.Contains(effect)) { return false; } if (Mathf.Abs(value) >= 1f) { return false; } return !Mathf.Approximately(value, Mathf.Round(value)); } internal static bool IsDeadField(string effect) { if (!string.IsNullOrEmpty(effect)) { return DeadFields.Contains(effect); } return false; } internal static bool PointsAtDrawback(string effect, float value) { if (value > 0f && !string.IsNullOrEmpty(effect)) { return LowerIsBetter.Contains(effect); } return false; } } internal sealed class Aett { internal const int Capacity = 8; internal string Name; internal readonly List<int> Indices = new List<int>(); } internal static class Cards { private static readonly List<Card> _all = new List<Card>(); private static readonly Dictionary<string, Card> _byId = new Dictionary<string, Card>(); private static readonly List<Aett> _aetts = new List<Aett>(); internal static IReadOnlyList<Card> All => _all; internal static IReadOnlyList<Aett> Aetts => _aetts; internal static bool Unavailable { get; private set; } internal static int Count => _all.Count; internal static Card Get(string id) { if (id == null || !_byId.TryGetValue(id, out var value)) { return null; } return value; } internal static void Load() { _all.Clear(); _byId.Clear(); _aetts.Clear(); Unavailable = false; string text = Path.Combine(Path.GetDirectoryName(typeof(Cards).Assembly.Location) ?? ".", "cards.txt"); if (!File.Exists(text)) { Unavailable = true; RistPlugin.Log.LogError((object)("cards.txt not found beside the DLL at " + text + " - no cards can be taken, and no card history will be reconciled. Reinstall the mod: the catalogue ships with it and is not optional.")); return; } string contents; string[] array; try { contents = File.ReadAllText(text); array = File.ReadAllLines(text); } catch (Exception ex) { Unavailable = true; RistPlugin.Log.LogError((object)("cards.txt at " + text + " could not be read (" + ex.Message + ") - no cards can be taken, and no card history will be reconciled.")); return; } if (RistPlugin.CorePresent) { DeclareCatalogue(contents); } int num = 0; string aett = ""; string[] array2 = array; foreach (string obj in array2) { num++; string text2 = obj.Trim(); if (text2.Length == 0 || text2[0] == '#') { continue; } if (text2.StartsWith("==", StringComparison.Ordinal)) { aett = text2.Substring(2).Trim(); continue; } string[] array3 = text2.Split(new char[1] { '|' }); if (array3.Length < 5) { RistPlugin.Log.LogWarning((object)("cards.txt line " + num + ": expected 5 fields, got " + array3.Length + " - skipped.")); continue; } Card card = new Card { Id = array3[0].Trim(), Name = array3[1].Trim(), Flavour = array3[2].Trim(), Effect = array3[3].Trim(), Aett = aett }; if (!float.TryParse(array3[4].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out card.PerRank)) { RistPlugin.Log.LogWarning((object)("cards.txt line " + num + ": '" + array3[4].Trim() + "' is not a number - skipped.")); } else if (card.Id.Length == 0) { RistPlugin.Log.LogWarning((object)("cards.txt line " + num + ": blank id - skipped.")); } else if (_byId.ContainsKey(card.Id)) { RistPlugin.Log.LogWarning((object)("cards.txt line " + num + ": duplicate id '" + card.Id + "' - skipped.")); } else { if (!Resolve(card.Effect, num, card.Id, out card.Field)) { continue; } if (array3.Length >= 8) { card.Sigil = array3[7].Trim(); } if (array3.Length >= 7) { card.BonusEffect = array3[5].Trim(); string text3 = array3[6].Trim(); if (card.BonusEffect.Length > 0) { if (!float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out card.BonusPerRank)) { RistPlugin.Log.LogWarning((object)("cards.txt line " + num + ": bonus value '" + text3 + "' is not a number - bonus dropped.")); card.BonusEffect = ""; } else if (!Resolve(card.BonusEffect, num, card.Id, out card.BonusField)) { card.BonusEffect = ""; } } } _all.Add(card); _byId[card.Id] = card; } } if (_all.Count == 0) { Unavailable = true; RistPlugin.Log.LogError((object)"cards.txt parsed to zero usable cards. Every line was blank, commented out or rejected - see the warnings above. No card can be taken, and no card history will be reconciled."); } else { RistPlugin.Log.LogInfo((object)("Loaded " + _all.Count + " cards from cards.txt.")); BuildAetts(); WarnAboutMissingLabels(); } } private static void BuildAetts() { Aett aett = null; List<string> list = new List<string>(); List<string> list2 = new List<string>(); HashSet<string> hashSet = new HashSet<string>(); int num = 0; for (int i = 0; i < _all.Count; i++) { string text = _all[i].Aett ?? ""; if (text.Length == 0) { num++; } if (aett == null || aett.Name != text || aett.Indices.Count >= 8) { int num2; if (aett != null) { num2 = ((aett.Name == text) ? 1 : 0); if (num2 != 0 && text.Length > 0 && !list.Contains(text)) { list.Add(text); } } else { num2 = 0; } if (num2 == 0 && text.Length > 0 && hashSet.Contains(text) && !list2.Contains(text)) { list2.Add(text); } if (aett != null) { hashSet.Add(aett.Name); } aett = new Aett { Name = text }; _aetts.Add(aett); } aett.Indices.Add(i); } if (list.Count > 0) { RistPlugin.Log.LogWarning((object)("These ættir hold more than " + 8 + " rists, so the panel stands each overflow as a second tower of the same name: " + string.Join(", ", list.ToArray()) + ". Split the heading in cards.txt.")); } if (list2.Count > 0) { RistPlugin.Log.LogWarning((object)("These ætt headings appear more than once in cards.txt, so each stands as more than one tower: " + string.Join(", ", list2.ToArray()) + ". Move the cards under a single heading.")); } if (num > 0) { RistPlugin.Log.LogWarning((object)(num + " rists in cards.txt stand under no \"== Name\" heading, so the panel shows them in towers with no name. Add a heading above them.")); } } private static void WarnAboutMissingLabels() { List<string> list = new List<string>(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); List<string> list4 = new List<string>(); foreach (Card item in _all) { if (Card.IsDeadField(item.Effect)) { list3.Add(item.Id + " (" + item.Effect + ")"); } if (Card.IsDeadField(item.BonusEffect)) { list3.Add(item.Id + " capstone (" + item.BonusEffect + ")"); } if (Card.PointsAtDrawback(item.Effect, item.PerRank)) { list4.Add(item.Id + " (" + item.Effect + " " + item.PerRank + ")"); } if (Card.PointsAtDrawback(item.BonusEffect, item.BonusPerRank)) { list4.Add(item.Id + " capstone (" + item.BonusEffect + " " + item.BonusPerRank + ")"); } if (!string.IsNullOrEmpty(item.Effect) && !Card.HasLabel(item.Effect)) { list.Add(item.Id + " (" + item.Effect + ")"); } if (!string.IsNullOrEmpty(item.BonusEffect) && !Card.HasLabel(item.BonusEffect)) { list.Add(item.Id + " capstone (" + item.BonusEffect + ")"); } if (Card.ReadsAsRawFraction(item.Effect, item.PerRank)) { list2.Add(item.Id + " (" + item.Effect + " " + item.PerRank + ")"); } if (Card.ReadsAsRawFraction(item.BonusEffect, item.BonusPerRank)) { list2.Add(item.Id + " capstone (" + item.BonusEffect + " " + item.BonusPerRank + ")"); } } if (list.Count > 0) { RistPlugin.Log.LogWarning((object)("These card effects have no readable name, so the panel shows the game's own field name to the player: " + string.Join(", ", list.ToArray()) + ". Add them to Cards.Labels.")); } if (list2.Count > 0) { RistPlugin.Log.LogWarning((object)("These card values are fractions but will be shown as raw numbers rather than percentages, so 0.05 reads as \"+0.1\": " + string.Join(", ", list2.ToArray()) + ". Add them to Cards.Percent.")); } if (list3.Count > 0) { RistPlugin.Log.LogWarning((object)("These card effects name a field the game never reads, so they do nothing whatever the tile says: " + string.Join(", ", list3.ToArray()) + ". See Card.DeadFields for what to use instead.")); } if (list4.Count > 0) { RistPlugin.Log.LogWarning((object)("These card values point the wrong way - on these fields negative is the benefit, so a positive value is a drawback: " + string.Join(", ", list4.ToArray()) + ". Flip the sign.")); } } private static bool Resolve(string effect, int lineNo, string id, out FieldInfo field) { field = null; if (Card.IsSpecialEffect(effect)) { if (Card.Specials.Contains(effect)) { return true; } RistPlugin.Log.LogWarning((object)("cards.txt line " + lineNo + ": unknown special '" + effect + "' - card '" + id + "' skipped.")); return false; } field = typeof(SE_Stats).GetField(effect, BindingFlags.Instance | BindingFlags.Public); if (field != null && field.FieldType == typeof(float)) { return true; } RistPlugin.Log.LogWarning((object)("cards.txt line " + lineNo + ": SE_Stats has no public float field '" + effect + "' - card '" + id + "' skipped.")); field = null; return false; } [MethodImpl(MethodImplOptions.NoInlining)] private static void DeclareCatalogue(string contents) { Suite.Data(contents, (string)null); } } [HarmonyPatch(typeof(Skills), "OnDeath")] internal static class DeathPenalty { private static bool Prefix() { return !RistConfig.RemoveDeathSkillLoss.Value; } } internal static class DeepDraught { internal static class Keep { [HarmonyPatch(typeof(Inventory), "RemoveOneItem")] [HarmonyPrefix] private static bool Removing(ItemData item) { if (_keep != null) { return item != _keep; } return true; } } internal const string Duration = "*mead:duration"; internal const string FullCask = "*mead:fullcask"; private static ItemData _keep; private static bool IsBuffMead(ItemData item) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (item == null || item.m_shared == null) { return false; } if (item.m_shared.m_food > 0f) { return false; } if ((int)item.m_shared.m_itemType != 2) { return false; } StatusEffect consumeStatusEffect = item.m_shared.m_consumeStatusEffect; SE_Stats val = (SE_Stats)(object)((consumeStatusEffect is SE_Stats) ? consumeStatusEffect : null); if ((Object)(object)val == (Object)null || ((object)val).GetType() != typeof(SE_Stats) || ((StatusEffect)val).m_ttl <= 0f) { return false; } if (val.m_healthUpFront != 0f || val.m_healthOverTime != 0f || val.m_healthPerTick != 0f) { return false; } if (val.m_staminaUpFront != 0f || val.m_staminaOverTime != 0f) { return false; } if (val.m_eitrUpFront != 0f || val.m_eitrOverTime != 0f) { return false; } return true; } [HarmonyPatch(typeof(Player), "ConsumeItem")] [HarmonyPrefix] private static void Before(Player __instance, ItemData item) { _keep = null; if (RistConfig.Enabled.Value && __instance == Player.m_localPlayer) { float num = Mathf.Clamp01(Effects.TotalFor("*mead:fullcask")); if (!(num <= 0f) && IsBuffMead(item) && Random.value < num) { _keep = item; } } } [HarmonyPatch(typeof(Player), "ConsumeItem")] [HarmonyPostfix] private static void After(Player __instance, ItemData item, bool __result) { bool flag = _keep != null; _keep = null; if (!__result || !RistConfig.Enabled.Value || __instance != Player.m_localPlayer || !IsBuffMead(item)) { return; } float num = Effects.TotalFor("*mead:duration"); if (num > 0f) { StatusEffect statusEffect = ((Character)__instance).GetSEMan().GetStatusEffect(item.m_shared.m_consumeStatusEffect.NameHash()); if ((Object)(object)statusEffect != (Object)null) { statusEffect.m_ttl *= 1f + num; } } if (flag) { ((Character)__instance).Message((MessageType)1, "The cask is still full", 0, (Sprite)null, false); } } [HarmonyPatch(typeof(Player), "ConsumeItem")] [HarmonyFinalizer] private static void Cleanup() { _keep = null; } } internal static class DevConsole { [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class Hook { private static void Postfix() { Register(); } } [CompilerGenerated] private static class <>O { public static ConsoleEvent <0>__OnCommand; } private static bool _registered; private static readonly string[][] AddsToZero = new string[12][] { new string[2] { "m_runStaminaDrainModifier", "run stamina" }, new string[2] { "m_jumpStaminaUseModifier", "jump stamina" }, new string[2] { "m_dodgeStaminaUseModifier", "dodge stamina" }, new string[2] { "m_swimStaminaUseModifier", "swim stamina" }, new string[2] { "m_sneakStaminaUseModifier", "sneak stamina" }, new string[2] { "m_attackStaminaUseModifier", "attack stamina" }, new string[2] { "m_blockStaminaUseModifier", "block stamina" }, new string[2] { "m_homeItemStaminaUseModifier", "tool stamina" }, new string[2] { "m_fallDamageModifier", "fall damage" }, new string[2] { "m_stealthModifier", "detection" }, new string[2] { "m_noiseModifier", "noise" }, new string[2] { "m_staggerModifier", "stagger taken" } }; private static void Register() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown if (!_registered) { _registered = true; object obj = <>O.<0>__OnCommand; if (obj == null) { ConsoleEvent val = OnCommand; <>O.<0>__OnCommand = val; obj = (object)val; } new ConsoleCommand("rist", "rist show | rist rank <card> <n> - this character's standing, and forcing a rank for a test", (ConsoleEvent)obj, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); RistPlugin.Log.LogInfo((object)"Console command 'rist' registered (needs devcommands, host or singleplayer)."); } } private static void OnCommand(ConsoleEventArgs args) { Terminal context = args.Context; if (!((Object)(object)context == (Object)null)) { switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "") { case "show": Show(context); return; case "rank": Rank(context, args); return; case "powers": Powers(context); return; } context.AddString("rist show - level, xp, ranks and the armour the game is using"); context.AddString("rist rank <card> <n> - force a card to exactly that rank"); context.AddString("rist powers - each forsaken power against every stone carved, and what reaches zero"); context.AddString("card ids are the first field of cards.txt: thickhide, steadyfoot, longstride..."); } } private static void Powers(Terminal term) { if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_StatusEffects == null || ObjectDB.instance.m_StatusEffects.Count == 0) { Say(term, "rist powers: no ObjectDB yet - load a world first."); return; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Card item in Cards.All) { if (item != null && !string.IsNullOrEmpty(item.Id)) { dictionary[item.Id] = RistConfig.MaxRank.Value; } } Dictionary<string, float> dictionary2 = Effects.TotalsFor(dictionary); float value = RistConfig.MinRunStaminaCost.Value; StringBuilder stringBuilder = new StringBuilder("rist powers: every stone at rank " + RistConfig.MaxRank.Value + " adds"); string[][] addsToZero = AddsToZero; foreach (string[] array in addsToZero) { dictionary2.TryGetValue(array[0], out var value2); if (value2 != 0f) { stringBuilder.Append(" " + array[1] + " " + Signed(value2)); } } Say(term, stringBuilder.ToString()); Dictionary<string, float> dictionary3 = new Dictionary<string, float>(); int num = 0; int num2 = 0; foreach (StatusEffect statusEffect in ObjectDB.instance.m_StatusEffects) { if ((Object)(object)statusEffect == (Object)null || ((Object)statusEffect).name == null || !((Object)statusEffect).name.StartsWith("GP_", StringComparison.Ordinal)) { continue; } num++; SE_Stats val = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null); if (val == null) { Say(term, " " + ((Object)statusEffect).name + " (" + ((object)statusEffect).GetType().Name + "): no stat modifiers, nothing to add up"); continue; } Say(term, " " + ((Object)statusEffect).name + ": " + Describe(val)); addsToZero = AddsToZero; foreach (string[] array2 in addsToZero) { float num3 = Read(val, array2[0]); if (num3 != 0f) { dictionary3.TryGetValue(array2[0], out var value3); dictionary3[array2[0]] = value3 + num3; dictionary2.TryGetValue(array2[0], out var value4); num2 += Judge(term, " ", array2, num3, value4, value); } } } if (num == 0) { Say(term, "rist powers: no GP_ status effects in ObjectDB - is this the stub ObjectDB?"); return; } if (dictionary3.Count > 0) { Say(term, " every power at once, as when several players cast on you:"); addsToZero = AddsToZero; foreach (string[] array3 in addsToZero) { if (dictionary3.TryGetValue(array3[0], out var value5)) { dictionary2.TryGetValue(array3[0], out var value6); num2 += Judge(term, " ", array3, value5, value6, value); } } } Say(term, (num2 == 0) ? ("rist powers: " + num + " powers read, nothing reaches zero") : ("rist powers: " + num + " powers read, " + num2 + " REACH ZERO")); } private static int Judge(Terminal term, string indent, string[] pair, float power, float rist, float floor) { float num = power + rist; string text = indent + pair[1] + ": power " + Signed(power) + ", rist " + Signed(rist) + ", together " + Signed(num); if (pair[0] == "m_runStaminaDrainModifier" && floor > 0f && num <= -1f + floor) { Say(term, text + " - floored at x" + floor.ToString("0.00", CultureInfo.InvariantCulture) + " by MinRunStaminaCost"); return 0; } if (power <= -1f) { Say(term, text + " - the power alone is already zero, as in vanilla"); return 0; } if (rist > -1f && num <= -1f) { Say(term, text + " - REACHES ZERO"); return 1; } Say(term, text); return 0; } private unsafe static string Describe(SE_Stats stats) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); FieldInfo[] fields = typeof(SE_Stats).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType != typeof(float)) { continue; } float num = (float)fieldInfo.GetValue(stats); float num2 = (Card.IsOneBased(fieldInfo.Name) ? 1f : 0f); if (!(Math.Abs(num - num2) < 0.0001f)) { string text = fieldInfo.Name + " " + num.ToString("0.###", CultureInfo.InvariantCulture); if (fieldInfo.Name == "m_damageModifier") { text = text + " on " + ((object)Unsafe.As<SkillType, SkillType>(ref stats.m_modifyAttackSkill)/*cast due to .constrained prefix*/).ToString(); } list.Add(text); } } if (stats.m_jumpModifier != Vector3.zero) { list.Add("m_jumpModifier " + ((Vector3)(ref stats.m_jumpModifier)).ToString("0.###")); } if (stats.m_mods != null) { foreach (DamageModPair mod in stats.m_mods) { DamageType type = mod.m_type; string? text2 = ((object)(*(DamageType*)(&type))/*cast due to .constrained prefix*/).ToString(); DamageModifier modifier = mod.m_modifier; list.Add(text2 + " " + ((object)(*(DamageModifier*)(&modifier))/*cast due to .constrained prefix*/).ToString()); } } if (list.Count != 0) { return string.Join(", ", list.ToArray()); } return "(no stat changes)"; } private static float Read(SE_Stats stats, string name) { FieldInfo field = typeof(SE_Stats).GetField(name, BindingFlags.Instance | BindingFlags.Public); if (!(field != null) || !(field.FieldType == typeof(float))) { return 0f; } return (float)field.GetValue(stats); } private static string Signed(float value) { return value.ToString("+0.00;-0.00;0.00", CultureInfo.InvariantCulture); } private static void Say(Terminal term, string line) { term.AddString(line); RistPlugin.Log.LogInfo((object)line); } private static void Show(Terminal term) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { term.AddString("rist: no player."); return; } term.AddString("level " + ClientState.Level + ", xp " + ClientState.Xp.ToString("0.#", CultureInfo.InvariantCulture) + ", owed " + ClientState.Owed + (Net.IsServer ? "" : " (client - the server holds the record)")); bool flag = false; foreach (KeyValuePair<string, int> rank in ClientState.Ranks) { if (rank.Value > 0) { flag = true; Card card = Cards.Get(rank.Key); term.AddString(" " + rank.Key + " rank " + rank.Value + ((card == null) ? " (no such card)" : (" - " + card.Name))); } } if (!flag) { term.AddString(" no ranks"); } term.AddString(Armour(localPlayer)); term.AddString(Moving(localPlayer)); } private static string Moving(Player player) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) SEMan sEMan = ((Character)player).GetSEMan(); float num = 1f; if (sEMan != null) { sEMan.ModifyRunStaminaDrain(1f, ref num, Vector3.zero, false); } float num2 = Sinews.VanillaJump(player); float num3 = ((num2 > 0f) ? (((Character)player).m_jumpForce / num2) : 1f); float num4 = num3 * num3; float num5 = Sinews.VanillaDelay(player) - player.m_staminaRegenDelay; float num6 = 1f; if (sEMan != null) { sEMan.ModifyStagger(1f, ref num6); } float num7 = Sinews.VanillaOverload(player); float num8 = ((num7 > 0f) ? (player.m_encumberedStaminaDrain / num7) : 1f); return "running x" + num.ToString("0.00", CultureInfo.InvariantCulture) + " delay " + num5.ToString("0.00", CultureInfo.InvariantCulture) + "s off (" + player.m_staminaRegenDelay.ToString("0.00", CultureInfo.InvariantCulture) + "s of " + Sinews.VanillaDelay(player).ToString("0.00", CultureInfo.InvariantCulture) + "s) jump height x" + num4.ToString("0.00", CultureInfo.InvariantCulture) + " (push " + ((Character)player).m_jumpForce.ToString("0.00", CultureInfo.InvariantCulture) + " of " + num2.ToString("0.00", CultureInfo.InvariantCulture) + ") stagger x" + num6.ToString("0.00", CultureInfo.InvariantCulture) + " overloaded x" + num8.ToString("0.00", CultureInfo.InvariantCulture); } private static string Armour(Player player) { float num = 0f; Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { foreach (ItemData equippedItem in inventory.GetEquippedItems()) { if (equippedItem != null && equippedItem.m_shared != null && !(equippedItem.m_shared.m_armor <= 0f)) { num += equippedItem.GetArmor(); } } } float bodyArmor = ((Character)player).GetBodyArmor(); float num2 = ((num > 0f) ? (bodyArmor / num) : 1f); float num3 = Effects.TotalFor("m_armorMultiplier"); float value = Effects.TotalFor("m_addArmor"); string text = "armour " + bodyArmor.ToString("0.0", CultureInfo.InvariantCulture) + " bare " + num.ToString("0.0", CultureInfo.InvariantCulture) + " game x" + num2.ToString("0.00", CultureInfo.InvariantCulture) + " rist x" + (1f + num3).ToString("0.00", CultureInfo.InvariantCulture); if (Math.Abs(value) > 0.0001f) { text = text + " and +" + value.ToString("0.#", CultureInfo.InvariantCulture) + " flat"; } return text; } private static void Rank(Terminal term, ConsoleEventArgs args) { if (args.Length < 4) { term.AddString("rist rank <card> <n>"); return; } if (!Net.IsServer) { term.AddString("rist: ranks live on the server, so this only works in singleplayer or when you host."); return; } string text = args[2]; Card card = Cards.Get(text); if (card == null) { term.AddString("rist: no card called '" + text + "'."); return; } if (!int.TryParse(args[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 0) { term.AddString("rist: '" + args[3] + "' is not a rank."); return; } int value = RistConfig.MaxRank.Value; if (result > value) { term.AddString("rist: MaxRank is " + value + "."); return; } if (!Net.LocalOwner(out var peer, out var owner)) { term.AddString("rist: this character has no record yet - wait a moment after spawning."); return; } RistRecord ristRecord = Ledger.For(owner); if (ristRecord == null) { term.AddString("rist: no ledger record for " + owner + "."); return; } int num = ristRecord.RankOf(text); ristRecord.SetRank(text, result); Ledger.Touch(); Net.PushState(peer, ristRecord); term.AddString(card.Name + ": rank " + num + " -> " + ristRecord.RankOf(text) + ". " + ristRecord.DraftsTaken + " picks spent, " + ristRecord.Owed + " owed."); } } internal static class Effects { private const string EffectName = "Rist"; private static readonly int EffectHash = StringExtensionMethods.GetStableHashCode("Rist"); private static SE_Stats _applied; private static string _appliedSignature; private static Player _appliedTo; private static readonly Dictionary<string, string[]> Spread = new Dictionary<string, string[]> { { "*stamina:move", new string[5] { "m_runStaminaDrainModifier", "m_jumpStaminaUseModifier", "m_dodgeStaminaUseModifier", "m_swimStaminaUseModifier", "m_sneakStaminaUseModifier" } }, { "*stamina:fight", new string[2] { "m_attackStaminaUseModifier", "m_blockStaminaUseModifier" } } }; internal static int ExtraRows { get; private set; } internal static void Reset() { if ((Object)(object)_applied != (Object)null) { Object.Destroy((Object)(object)_applied); } _applied = null; _appliedSignature = null; _appliedTo = null; Sinews.Reset(); } internal static void Apply(Player player, Dictionary<string, int> ranks) { if ((Object)(object)player == (Object)null) { return; } string text = Signature(ranks); if (player != _appliedTo || !(text == _appliedSignature)) { _appliedTo = player; _appliedSignature = text; ApplyStats(player, ranks); ApplyInventoryRows(player, ranks); ApplyHorizon(ranks); ApplySinews(player, ranks); if (RistConfig.Verbose.Value) { RistPlugin.Log.LogInfo((object)("Applied cards: " + ((text.Length == 0) ? "(none)" : text))); } } } private static Dictionary<string, float> Totals(Dictionary<string, int> ranks) { Dictionary<string, float> dictionary = new Dictionary<string, float>(); if (ranks == null) { return dictionary; } foreach (KeyValuePair<string, int> rank in ranks) { if (rank.Value <= 0) { continue; } Card card = Cards.Get(rank.Key); if (card == null) { continue; } Add(dictionary, card.Effect, card.PerRank * (float)rank.Value); if (card.HasBonus) { int num = Card.BonusTimes(rank.Value); if (num > 0) { Add(dictionary, card.BonusEffect, card.BonusPerRank * (float)num); } } } return dictionary; } private static void Add(Dictionary<string, float> totals, string effect, float amount) { if (string.IsNullOrEmpty(effect)) { return; } if (Spread.TryGetValue(effect, out var value)) { string[] array = value; foreach (string effect2 in array) { Add(totals, effect2, amount); } } else { totals.TryGetValue(effect, out var value2); totals[effect] = value2 + amount; } } internal static Dictionary<string, float> TotalsFor(Dictionary<string, int> ranks) { return Totals(ranks); } internal static float TotalFor(string effect) { if (!ClientState.Known || string.IsNullOrEmpty(effect)) { return 0f; } if (!Totals(ClientState.Ranks).TryGetValue(effect, out var value)) { return 0f; } return value; } private static void ApplyStats(Player player, Dictionary<string, int> ranks) { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan == null) { return; } Dictionary<FieldInfo, float> dictionary = new Dictionary<FieldInfo, float>(); foreach (KeyValuePair<string, float> item in Totals(ranks)) { if (!Card.IsSpecialEffect(item.Key)) { FieldInfo field = typeof(SE_Stats).GetField(item.Key, BindingFlags.Instance | BindingFlags.Public); if (!(field == null) && !(field.FieldType != typeof(float))) { dictionary[field] = item.Value; } } } sEMan.RemoveStatusEffect(EffectHash, true); if ((Object)(object)_applied != (Object)null) { Object.Destroy((Object)(object)_applied); _applied = null; } if (dictionary.Count == 0) { return; } SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)val).name = "Rist"; ((StatusEffect)val).m_name = "Rist"; ((StatusEffect)val).m_ttl = 0f; val.m_raiseSkill = (SkillType)999; val.m_modifyAttackSkill = (SkillType)999; val.m_skillLevel = (SkillType)999; foreach (KeyValuePair<FieldInfo, float> item2 in dictionary) { float num = (Card.IsOneBased(item2.Key.Name) ? (1f + item2.Value) : item2.Value); item2.Key.SetValue(val, num); } sEMan.AddStatusEffect((StatusEffect)(object)val, false, 0, 0f, (short)(-1)); _applied = val; } private static void ApplyInventoryRows(Player player, Dictionary<string, int> ranks) { Totals(ranks).TryGetValue("*inventoryrow", out var value); ExtraRows = Mathf.Max(0, Mathf.RoundToInt(value)); if (RistPlugin.CorePresent) { ClaimThroughCore(ExtraRows); } else { OwnInventoryRows.Claimed = ExtraRows; } } private static void ApplyHorizon(Dictionary<string, int> ranks) { Dictionary<string, float> dictionary = Totals(ranks); dictionary.TryGetValue("*exploreradius", out var value); dictionary.TryGetValue("*windcone", out var value2); dictionary.TryGetValue("*rowspeed", out var value3); Horizon.ExtraExplore = Mathf.Max(0f, value); Horizon.ConeNarrowing = Mathf.Clamp01(value2); Horizon.RowBonus = Mathf.Max(0f, value3); } private static void ApplySinews(Player player, Dictionary<string, int> ranks) { Dictionary<string, float> dictionary = Totals(ranks); dictionary.TryGetValue("*staminadelay", out var value); dictionary.TryGetValue("*jumpheight", out var value2); dictionary.TryGetValue("*overloaded", out var value3); Sinews.DelayCut = Mathf.Max(0f, value); Sinews.JumpBonus = Mathf.Max(0f, value2); Sinews.OverloadMod = Mathf.Min(0f, value3); Sinews.Apply(player); } [MethodImpl(MethodImplOptions.NoInlining)] private static void ClaimThroughCore(int rows) { InventoryRows.Claim("ezomic.valheim.rist", rows); } private static string Signature(Dictionary<string, int> ranks) { if (ranks == null || ranks.Count == 0) { return ""; } List<string> list = new List<string>(ranks.Keys); list.Sort(); StringBuilder stringBuilder = new StringBuilder(); foreach (string item in list) { if (stringBuilder.Length > 0) { stringBuilder.Append(','); } stringBuilder.Append(item).Append(':').Append(ranks[item]); } return stringBuilder.ToString(); } } internal static class Gate { private static readonly HashSet<string> Baselined = new HashSet<string>(StringComparer.Ordinal); internal static bool HasBaseline(string owner) { if (owner != null) { return Baselined.Contains(owner); } return false; } internal static void Forget() { Baselined.Clear(); } internal static string LocalSkills() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected I4, but got Unknown Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return ""; } Skills skills = ((Character)localPlayer).GetSkills(); if ((Object)(object)skills == (Object)null) { return ""; } StringBuilder stringBuilder = new StringBuilder(); foreach (Skill skill in skills.GetSkillList()) { if (skill != null && skill.m_info != null) { if (stringBuilder.Length > 0) { stringBuilder.Append(','); } stringBuilder.Append((int)skill.m_info.m_skill).Append(':').Append(skill.m_level.ToString("R", CultureInfo.InvariantCulture)); } } return stringBuilder.ToString(); } internal static void Judge(long sender, string owner, string facts, string skills) { if (!RistConfig.CheckSkillBaseline.Value || string.IsNullOrEmpty(owner)) { return; } Dictionary<int, float> dictionary = ParseSkills(skills); if (dictionary == null) { return; } RistRecord ristRecord = Ledger.For(owner); if (ristRecord == null) { return; } bool flag = !ristRecord.HasSnapshot; Baselined.Add(owner); int num = 0; foreach (KeyValuePair<int, float> item in dictionary) { if (!ristRecord.Snapshot.TryGetValue(item.Key, out var value) || !(item.Value <= value)) { ristRecord.Snapshot[item.Key] = item.Value; num++; } } if (num > 0) { Ledger.Touch(); } if (flag) { RistPlugin.Log.LogInfo((object)("Baseline adopted for " + owner + " (" + dictionary.Count + " skills).")); } else if (num > 0 && RistConfig.Verbose.Value) { RistPlugin.Log.LogInfo((object)("Baseline for " + owner + " raised on " + num + " skill(s).")); } bool flag2 = Recompute(owner, ristRecord); if (Credit(sender, owner, ristRecord, dictionary) || flag2) { Net.PushState(sender, ristRecord); } } internal static bool Recompute(string owner, RistRecord rec) { if (rec == null) { return false; } string text = (RistConfig.WeightGeneration.Value ?? "").Replace("|", "/").Trim(); if ((rec.WeightGen ?? "") == text) { return false; } if (!rec.HasSnapshot) { return false; } float xp = rec.Xp; int level = rec.Level; rec.Xp = Weights.WorthOf(rec.Snapshot); rec.WeightGen = text; Ledger.Touch(); RistPlugin.Log.LogInfo((object)("Re-priced " + owner + " at weight generation '" + text + "': " + xp.ToString("0") + " -> " + rec.Xp.ToString("0") + " xp, Rist level " + level + " -> " + rec.Level + " (" + rec.DraftsTaken + " cards kept, " + rec.Owed + " to spend).")); return true; } private static bool Credit(long sender, string owner, RistRecord rec, Dictionary<int, float> reported) { if (!RistConfig.CreditExistingSkills.Value) { return false; } float num = Weights.WorthOf(reported); if (num <= rec.Xp + 0.001f) { return false; } int level = rec.Level; rec.Xp = num; Ledger.Touch(); RistPlugin.Log.LogInfo((object)("Credited " + owner + " for skills already held: " + num.ToString("0") + " xp, Rist level " + level + " -> " + rec.Level + ".")); return true; } private static Dictionary<int, float> ParseSkills(string wire) { if (wire == null) { return null; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); string[] array = wire.Split(new char[1] { ',' }); foreach (string text in array) { if (text.Length != 0) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && int.TryParse(array2[0], out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { dictionary[result] = result2; } } } return dictionary; } } internal static class Horizon { [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(Vector3), typeof(float) })] internal static class Radius { [HarmonyPrefix] private static void Widen(ref float radius) { if (ExtraExplore > 0f) { radius *= 1f + ExtraExplore; } } } [HarmonyPatch(typeof(Ship), "GetWindAngleFactor")] internal static class WindAngle { [HarmonyPostfix] private static void Narrow(Ship __instance, ref float __result) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && !((Object)(object)EnvMan.instance == (Object)null) && !(ConeNarrowing <= 0f) && LocalIsHelmsman(__instance)) { float num = Vector3.Dot(EnvMan.instance.GetWindDir(), -((Component)__instance).transform.forward); if (!(num <= 0f)) { Edges(out var lo, out var hi); float num2 = Mathf.Lerp(0.7f, 1f, 1f - Mathf.Abs(num)); float num3 = 1f - Mathf.Clamp01((num - lo) / (hi - lo)); __result = Mathf.Clamp(num2 * num3, __result, num2); } } } } [HarmonyPatch(typeof(Ship), "GetSailForce")] internal static class Sail { private static FieldRef<Ship, Vector3> _force; private static FieldRef<Ship, Vector3> _velocity; private static bool _bound; private static bool _broken; private static bool Bound() { if (_bound) { return !_broken; } _bound = true; try { _force = AccessTools.FieldRefAccess<Ship, Vector3>("m_sailForce"); _velocity = AccessTools.FieldRefAccess<Ship, Vector3>("m_windChangeVelocity"); } catch (Exception ex) { _broken = true; RistPlugin.Log.LogWarning((object)("Weatherly cannot bend the sail, the ship's sail fields have moved. The dead zone still narrows. " + ex.Message)); } return !_broken; } [HarmonyPrefix] private static bool Bend(Ship __instance, float sailSize, ref Vector3 __result) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)EnvMan.instance == (Object)null) { return true; } if (ConeNarrowing <= 0f || !LocalIsHelmsman(__instance)) { return true; } Vector3 windDir = EnvMan.instance.GetWindDir(); Vector3 forward = ((Component)__instance).transform.forward; float num = Vector3.Dot(windDir, -forward); Edges(out var _, out var hi); if (num <= 0.75f || num >= hi) { return true; } if (!Bound()) { return true; } float num2 = Mathf.Lerp(0.25f, 1f, EnvMan.instance.GetWindIntensity()); float num3 = __instance.GetWindAngleFactor() * num2; Vector3 val = windDir + forward; Vector3 val2 = Vector3.Lerp((((Vector3)(ref val)).sqrMagnitude < 1E-06f) ? forward : ((Vector3)(ref val)).normalized, forward, Mathf.Clamp01(ConeNarrowing)); Vector3 val3 = ((Vector3)(ref val2)).normalized * (num3 * __instance.m_sailForceFactor * sailSize); ref Vector3 reference = ref _force.Invoke(__instance); ref Vector3 reference2 = ref _velocity.Invoke(__instance); reference = Vector3.SmoothDamp(reference, val3, ref reference2, 1f, 99f); __result = reference; return false; } } [HarmonyPatch(typeof(Hud), "UpdateShipHud")] internal static class Ring { private static Transform _root; private static readonly List<RingWarp> Warps = new List<RingWarp>(); private static bool _warned; [HarmonyPostfix] private static void Track(Hud __instance, Player player) { if ((Object)(object)__instance == (Object)null) { return; } RectTransform shipWindIndicatorRoot = __instance.m_shipWindIndicatorRoot; if ((Object)(object)shipWindIndicatorRoot == (Object)null || !((Component)shipWindIndicatorRoot).gameObject.activeInHierarchy) { return; } if ((Object)(object)shipWindIndicatorRoot != (Object)(object)_root || Stale()) { Find((Transform)(object)shipWindIndicatorRoot); } float narrowing = 0f; if ((Object)(object)player != (Object)null) { Ship controlledShip = player.GetControlledShip(); if ((Object)(object)controlledShip != (Object)null && LocalIsHelmsman(controlledShip)) { narrowing = ConeNarrowing; } } foreach (RingWarp warp in Warps) { if ((Object)(object)warp != (Object)null) { warp.SetNarrowing(narrowing); } } } private static bool Stale() { foreach (RingWarp warp in Warps) { if ((Object)(object)warp == (Object)null) { return true; } } return false; } private static void Find(Transform root) { _root = root; Warps.Clear(); Image[] componentsInChildren = ((Component)root).GetComponentsInChildren<Image>(true); RingWarp item = default(RingWarp); foreach (Image val in componentsInChildren) { if ((Object)(object)val == (Object)null || (Object)(object)val.sprite == (Object)null) { continue; } string name = ((Object)val.sprite).name; if (!(name != "ship_circle") || !(name != "ship_circle_bw")) { if (!((Component)val).TryGetComponent<RingWarp>(ref item)) { item = ((Component)val).gameObject.AddComponent<RingWarp>(); } Warps.Add(item); } } if (Warps.Count <= 0 && !_warned) { _warned = true; RistPlugin.Log.LogWarning((object)"Weatherly cannot redraw the wind ring: no ship_circle or ship_circle_bw sprite under the ship HUD. The dead zone still narrows; the ring will show vanilla's."); } } } [HarmonyPatch(typeof(Ship), "CustomFixedUpdate")] internal static class Row { [HarmonyPrefix] private static void Scale(Ship __instance, out float __state) { __state = (((Object)(object)__instance != (Object)null) ? __instance.m_backwardForce : 0f); if (!((Object)(object)__instance == (Object)null) && !(RowBonus <= 0f) && __instance.IsOwner() && LocalIsHelmsman(__instance)) { float num = 1f + RowBonus; __instance.m_backwardForce = __state * num * num; } } [HarmonyFinalizer] private static Exception Restore(Ship __instance, float __state, Exception __exception) { if ((Object)(object)__instance != (Object)null) { __instance.m_backwardForce = __state; } return __exception; } } internal const string ExploreRadius = "*exploreradius"; internal const string WindCone = "*windcone"; internal const string RowSpeed = "*rowspeed"; internal static float ExtraExplore; internal static float ConeNarrowing; internal static float RowBonus; private static readonly float VanillaLiveAngle = Mathf.Acos(0.75f) * 57.29578f; private static readonly float VanillaDeadAngle = Mathf.Acos(0.8f) * 57.29578f; private const float MaxNarrowing = 0.8f; internal const float MaxNarrowingValue = 0.8f; private const float VanillaLiveDot = 0.75f; internal static float VanillaLiveAngleDeg => VanillaLiveAngle; internal static float VanillaDeadAngleDeg => VanillaDeadAngle; private static bool LocalIsHelmsman(Ship ship) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)ship == (Object)null || (Object)(object)localPlayer == (Object)null || (Object)(object)ship.m_shipControlls == (Object)null) { return false; } return ship.m_shipControlls.GetUser() == localPlayer.GetPlayerID(); } internal static void EdgeAngles(out float liveAngle, out float deadAngle) { float num = 1f - Mathf.Clamp(ConeNarrowing, 0f, 0.8f); liveAngle = VanillaLiveAngle * num; deadAngle = VanillaDeadAngle * num; } private static void Edges(out float lo, out float hi) { EdgeAngles(out var liveAngle, out var deadAngle); lo = Mathf.Cos(liveAngle * ((float)Math.PI / 180f)); hi = Mathf.Cos(deadAngle * ((float)Math.PI / 180f)); } } internal static class HudBar { private const float BorderBuffer = 16f; private static GameObject _root; private static RectTransform _rect; private static RectTransform _fastBar; private static RectTransform _slowBar; private static Image _fastFill; private static Image _slowFill; private static CanvasGroup _group; private static TMP_Text _text; private static Animator _animator; private static Canvas _canvas; private static bool _pulsing; private static bool _failed; private static int _shownLevel = -1; private static int _shownPercent = -1; private static bool _shownOwed; private static float _sizedAt; private static float _trail = -1f; private const float TrailSpeed = 0.5f; private static bool _uprightAt; private static string _tintedAt; private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4]; private static float _loggedTop = float.NaN; internal static bool Live => (Object)(object)_root != (Object)null; internal static bool HasText => (Object)(object)_text != (Object)null; internal static Vector2? ScreenCentre { get { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rect == (Object)null) { return null; } Vector2 val = RectTransformUtility.WorldToScreenPoint(((Object)(object)_canvas != (Object)null && (int)_canvas.renderMode != 0) ? _canvas.worldCamera : null, ((Transform)_rect).position); return new Vector2(val.x, (float)Screen.height - val.y); } } internal static float? ScreenTop { get { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rect == (Object)null) { return null; } Camera val = (((Object)(object)_canvas != (Object)null && (int)_canvas.renderMode != 0) ? _canvas.worldCamera : null); float num = float.MaxValue; RectTransform[] componentsInChildren = ((Component)_rect).GetComponentsInChildren<RectTransform>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].GetWorldCorners(Corners); Vector3[] corners = Corners; foreach (Vector3 val2 in corners) { Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val, val2); float num2 = (float)Screen.height - val3.y; if (num2 < num) { num = num2; } } } if (num == float.MaxValue) { return null; } if (RistConfig.Verbose.Value && !Mathf.Approximately(num, _loggedTop)) { _loggedTop = num; RistPlugin.Log.LogInfo((object)("Bar top edge measured at y=" + Mathf.RoundToInt(num) + " of " + Screen.height + ", canvas scale " + Scale.ToString("0.00") + ".")); } return num; } } internal static float Scale { get { if (!((Object)(object)_canvas != (Object)null)) { return 1f; } return _canvas.scaleFactor; } } internal static float HalfLength { get { float num = (((Object)(object)_canvas != (Object)null) ? _canvas.scaleFactor : 1f); return Mathf.Max(16f, RistConfig.BarSize.Value) * 0.5f * num; } } internal static void Update() { if (!RistConfig.Enabled.Value || !RistConfig.ShowXpBar.Value || !RistConfig.VanillaBar.Value) { Drop(); } else if ((Object)(object)Hud.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { Drop(); } else { if ((Object)(object)_root == (Object)null && !Build()) { return; } bool flag = Visible(); if ((Object)(object)_group != (Object)null) { _group.alpha = (flag ? 1f : 0f); } if (flag) { Place(); if (!Mathf.Approximately(_sizedAt, RistConfig.BarSize.Value)) { Size(); } if (_uprightAt != RistConfig.BarUpright.Value) { Lay(); } if (_tintedAt != RistConfig.BarColour.Value) { Colour(); } float num = Mathf.Clamp01(Levels.Progress(ClientState.Xp)); Fill(num); int num2 = Mathf.Clamp(Mathf.RoundToInt(num * 100f), 0, 100); bool hasPick = ClientState.HasPick; if ((Object)(object)_text != (Object)null && (_shownLevel != ClientState.Level || _shownPercent != num2 || _shownOwed != hasPick)) { _shownLevel = ClientState.Level; _shownPercent = num2; _shownOwed = hasPick; _text.text = _shownLevel + " · " + num2 + "%" + (ClientState.HasPick ? " ★" : ""); } Announce(); } } } private static bool Visible() { if (!ClientState.Known) { return false; } if (((Character)Player.m_localPlayer).IsDead()) { return false; } if (((Character)Player.m_localPlayer).InCutscene()) { return false; } return !Hud.instance.m_userHidden; } private static void Announce() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_fastFill == (Object)null) { return; } if (!ClientState.HasPick) { if (_pulsing) { _pulsing = false; Colour(); } } else { _pulsing = true; float num = Mathf.Max(1f, RistConfig.BarFlashSeconds.Value); float num2 = Mathf.PingPong(Time.time / num * 2f, 1f); Color val = RistConfig.BarTint(); ((Graphic)_fastFill).color = Color.Lerp(val, Color.white, num2 * 0.5f); } } private static bool Build() { if (_failed) { return false; } RectTransform val = (((Object)(object)Hud.instance.m_eitrBarRoot != (Object)null) ? Hud.instance.m_eitrBarRoot : Hud.instance.m_staminaBar2Root); if ((Object)(object)val == (Object)null || (Object)(object)((Transform)val).parent == (Object)null) { Fail("no upright bar to clone from - falling back to the plain bar."); return false; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Transform)val).parent); ((Object)val2).name = "RistXpBar"; val2.SetActive(true); _rect = val2.GetComponent<RectTransform>(); _canvas = val2.GetComponentInParent<Canvas>(); GuiBar val3 = null; GuiBar val4 = null; GuiBar[] componentsInChildren = val2.GetComponentsInChildren<GuiBar>(true); foreach (GuiBar val5 in componentsInChildren) { if (val5.m_smoothDrain || val5.m_smoothFill) { if ((Object)(object)val4 == (Object)null) { val4 = val5; } } else if ((Object)(object)val3 == (Object)null) { val3 = val5; } } if ((Object)(object)val3 == (Object)null) { val3 = val4; } if ((Object)(object)val4 == (Object)null) { val4 = val3; } if ((Object)(object)val3 == (Object)null) { Object.Destroy((Object)(object)val2); Fail("the cloned bar has no GuiBar - falling back to the plain bar."); return false; } _fastBar = val3.m_bar; _slowBar = val4.m_bar; _fastFill = (((Object)(object)_fastBar != (Object)null) ? ((Component)_fastBar).GetComponent<Image>() : null); _slowFill = (((Object)(object)_slowBar != (Object)null) ? ((Component)_slowBar).GetComponent<Image>() : null); if ((Object)(object)val4 != (Object)(object)val3) { Object.DestroyImmediate((Object)(object)val4); } Object.DestroyImmediate((Object)(object)val3); _text = val2.GetComponentInChildren<TMP_Text>(true); _animator = val2.GetComponent<Animator>(); if ((Object)(object)_animator == (Object)null) { _animator = val2.GetComponentInChildren<Animator>(true); } Size(); Colour(); Lay(); _group = val2.GetComponent<CanvasGroup>(); if ((Object)(object)_group == (Object)null) { _group = val2.AddComponent<CanvasGroup>(); } _group.blocksRaycasts = false; _group.interactable = false; Unfade(val2); _root = val2; _shownLevel = -1; _trail = -1f; RistPlugin.Log.LogInfo((object)("Experience bar cloned from " + ((Object)val).name + ".")); return true; } private static void Unfade(GameObject go) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_animator != (Object)null) { Object.Destroy((Object)(object)_animator); } _animator = null; Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } } CanvasGroup[] componentsInChildren2 = go.GetComponentsInChildren<CanvasGroup>(true); foreach (CanvasGroup val2 in componentsInChildren2) { if (val2.alpha < 0.05f) { val2.alpha = 1f; } } Graphic[] componentsInChildren3 = go.GetComponentsInChildren<Graphic>(true); foreach (Graphic val3 in componentsInChildren3) { Color color = val3.color; if (!(color.a >= 0.05f)) { color.a = 1f; val3.color = color; } } if (RistConfig.Verbose.Value) { RistPlugin.Log.LogInfo((object)"Cloned bar detached from the donor's animator and brought up by hand."); } } private static void Size() { _sizedAt = RistConfig.BarSize.Value; float num = Mathf.Max(16f, _sizedAt); _rect.SetSizeWithCurrentAnchors((Axis)0, num + 16f); if (RistConfig.Verbose.Value) { RistPlugin.Log.LogInfo((object)("Bar sized to " + num + ".")); } } private static void Fill(float progress) { float num = Mathf.Max(16f, RistConfig.BarSize.Value); if (_trail < 0f || progress > _trail) { _trail = progress; } else { _trail = Mathf.MoveTowards(_trail, progress, Time.deltaTime * 0.5f); } Draw(_slowBar, num * Mathf.Max(_trail, progress)); Draw(_fastBar, num * progress); } private static void Draw(RectTransform bar, float width) { if (!((Object)(object)bar == (Object)null)) { bar.SetSizeWithCurrentAnchors((Axis)0, Mathf.Max(0f, width)); } } private static void Lay() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) _uprightAt = RistConfig.BarUpright.Value; if (!((Object)(object)_rect == (Object)null)) { ((Transform)_rect).rotation = (_uprightAt ? Quaternion.Euler(0f, 0f, 90f) : Quaternion.identity); } } private static void Colour() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) _tintedAt = RistConfig.BarColour.Value; Color val = RistConfig.BarTint(); Tint(_fastFill, val); Tint(_slowFill, new Color(val.r * 0.55f, val.g * 0.55f, val.b * 0.55f, val.a)); if ((Object)(object)_text != (Object)null) { ((Graphic)_text).color = val; } } private unsafe static void Tint(Image image, Color colour) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)image == (Object)null)) { if (RistConfig.Verbose.Value && ((Graphic)image).color != colour) { ManualLogSource log = RistPlugin.Log; string[] obj = new string[9] { "Bar fill '", ((Object)image).name, "' was ", ((object)((Graphic)image).color/*cast due to .constrained prefix*/).ToString(), " (sprite ", ((Object)(object)image.sprite != (Object)null) ? ((Object)image.sprite).name : "none", "); set to ", null, null }; Color val = colour; obj[7] = ((object)(*(Color*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[8] = "."; log.LogInfo((object)string.Concat(obj)); } ((Graphic)image).color = colour; } } private static void Place() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Transform)_rect).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val == (Object)null) { return; } bool flag = ((Object)(object)Hud.instance.m_buildHud != (Object)null && Hud.instance.m_buildHud.activeSelf) || ((Object)(object)Hud.instance.m_shipHudRoot != (Object)null && Hud.instance.m_shipHudRoot.activeSelf); Camera val2 = (((Object)(object)_canvas != (Object)null && (int)_canvas.renderMode != 0) ? _canvas.worldCamera : null); float scale = Scale; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(RistConfig.BarPosX.Value * scale, (RistConfig.BarPosY.Value + (flag ? RistConfig.BarBuildRaise.Value : 0f)) * scale); if (RistConfig.BarFollowStamina.Value) { RectTransform staminaBar2Root = Hud.instance.m_staminaBar2Root; if ((Object)(object)staminaBar2Root != (Object)null) { Vector2 val4 = RectTransformUtility.WorldToScreenPoint(val2, ((Transform)staminaBar2Root).position); ((Vector2)(ref val3))..ctor(val4.x + RistConfig.BarOffsetX.Value * scale, val4.y - RistConfig.BarOffsetY.Value * scale); } } Vector3 position = default(Vector3); if (RectTransformUtility.ScreenPointToWorldPointInRectangle(val, val3, val2, ref position)) { ((Transform)_rect).position = position; } } private static void Fail(string why) { _failed = true; RistPlugin.Log.LogWarning((object)("Rist: " + why)); } internal static void Drop() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; _rect = null; _fastBar = null; _slowBar = null; _fastFill = null; _slowFill = null; _group = null; _pulsing = false; _text = null; _animator = null; _canvas = null; _shownLevel = -1; _trail = -1f; _shownPercent = -1; _sizedAt = 0f; _tintedAt = null; _failed = false; } } internal static class InfoTab { [CompilerGenerated] private static class <>O { public static UnityAction <0>__Open; } private static GameObject _tab; private static InventoryGui _seen; private static Sprite _icon; private static bool _failed; internal static void Update() { if (!_failed && RistConfig.Enabled.Value && RistConfig.ShowInfoTab.Value) { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_infoPanel == (Object)null) { _seen = null; } else if (instance != _seen || !((Object)(object)_tab != (Object)null)) { _seen = instance; Build(instance); } } } private static void Build(InventoryGui gui) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown Button val = Donor(gui); if ((Object)(object)val == (Object)null) { _failed = true; RistPlugin.Log.LogWarning((object)"No compendium tab to clone, and there is no keybind any more - the rists panel has no way in. That is a bug rather than a setting; please report it."); return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent); ((Object)val2).name = "RistTab"; Button component = val2.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { ((UnityEventBase)component.onClick).RemoveAllListeners(); ButtonClickedEvent onClick = component.onClick; object obj = <>O.<0>__Open; if (obj == null) { UnityAction val3 = Open; <>O.<0>__Open = val3; obj = (object)val3; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } Localize[] componentsInChildren = val2.GetComponentsInChildren<Localize>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } Icon(val2, val); Place(gui, val2, val); _tab = val2; RistPlugin.Log.LogInfo((object)"Rists tab added to the compendium bar."); } private static Button Donor(InventoryGui gui) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) Button result = null; float num = float.MinValue; Button[] componentsInChildren = ((Component)gui.m_infoPanel).GetComponentsInChildren<Button>(true); foreach (Button val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(((Object)val).name == "RistTab")) { RectTransform component = ((Component)val).GetComponent<RectTransform>(); if (!((Object)(object)component == (Object)null) && component.anchoredPosition.x > num) { num = component.anchoredPosition.x; result = val; } } } return result; } private static void Place(InventoryGui gui, GameObject tab, Button donor) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) RectTransform component = tab.GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { return; } List<RectTransform> list = new List<RectTransform>(); Selectable[] componentsInChildren = ((Component)gui.m_infoPanel).GetComponentsInChildren<Selectable>(true); foreach (Selectable val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { RectTransform component2 = ((Component)val).GetComponent<RectTransform>(); if (!((Object)(object)component2 == (Object)null) && !((Object)(object)component2 == (Object)(object)component) && !list.Contains(component2)) { list.Add(component2); } } } if (list.Count != 0) { list.Sort((RectTransform a, RectTransform b) => a.anchoredPosition.x.CompareTo(b.anchoredPosition.x)); list.Add(component); float num = Pitch(list); float y = list[0].anchoredPosition.y; float num2 = (0f - num) * (float)(list.Count - 1) * 0.5f; for (int num3 = 0; num3 < list.Count; num3++) { list[num3].anchoredPosition = new Vector2(num2 + (float)num3 * num, y); } RistPlugin.Log.LogInfo((object)("Compendium bar re-spaced: " + list.Count + " icons at " + (int)num + "px.")); } } private static float Pitch(List<RectTransform> icons) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) for (int i = 1; i < icons.Count; i++) { float num = icons[i].anchoredPosition.x - icons[i - 1].anchoredPosition.x; if (num > 1f) { return num; } } Rect rect = icons[0].rect; return ((Rect)(ref rect)).width * 1.15f; } private static void Icon(GameObject tab, Button donor) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_icon == (Object)null) { Texture2D val = Algiz(); _icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); ((Object)_icon).name = "RistAlgiz"; } Button component = tab.GetComponent<Button>(); Image val2 = (Image)(((Object)(object)component != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); Rect rect; Image[] componentsInChildren; if ((Object)(object)val2 == (Object)null) { componentsInChildren = tab.GetComponentsInChildren<Image>(true); foreach (Image val3 in componentsInChildren) { if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).gameObject == (Object)(object)tab || ((Object)val3).name == "Background") { continue; } if (!((Object)(object)val2 == (Object)null)) { rect = ((Graphic)val3).rectTransform.rect; float width = ((Rect)(ref rect)).width; rect = ((Graphic)val2).rectTransform.rect; if (!(width < ((Rect)(ref rect)).width)) { continue; } } val2 = val3; } RistPlugin.Log.LogWarning((object)("The tab's target graphic was not an Image; fell back to '" + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "nothing") + "'.")); } if ((Object)(object)val2 == (Object)null) { RistPlugin.Log.LogWarning((object)"No glyph layer on the cloned tab - it will still open the rists, wearing the donor's picture."); return; } val2.sprite = _icon; ((Graphic)val2).color = Color.white; val2.preserveAspect = true; ((Behaviour)val2).enabled = true; ((Graphic)val2).raycastTarget = true; if (!RistConfig.Verbose.Value) { return; } componentsInChildren = ((Component)donor).GetComponentsInChildren<Image>(true); foreach (Image val4 in componentsInChildren) { if (!((Object)(object)val4 == (Object)null)) { ManualLogSource log = RistPlugin.Log; string[] obj = new string[10] { " donor layer '", ((Object)val4).name, "' ", ((Behaviour)val4).enabled ? "on" : "off", " ", null, null, null, null, null }; rect = ((Graphic)val4).rectTransform.rect; obj[5] = ((object)((Rect)(ref rect)).size/*cast due to .constrained prefix*/).ToString(); obj[6] = " colour "; obj[7] = ((object)((Graphic)val4).color/*cast due to .constrained prefix*/).ToString(); obj[8] = " sprite "; obj[9] = (((Object)(object)val4.sprite != (Object)null) ? ((Object)val4.sprite).name : "none"); log.LogInfo((object)string.Concat(obj)); } } ManualLogSource log2 = RistPlugin.Log; string[] obj2 = new string[8] { " donor '", ((Object)donor).name, "' normal ", null, null, null, null, null }; ColorBlock colors = ((Selectable)donor).colors; obj2[3] = ((object)((ColorBlock)(ref colors)).normalColor/*cast due to .constrained prefix*/).ToString(); obj2[4] = ", highlighted "; colors = ((Selectable)donor).colors; obj2[5] = ((object)((ColorBlock)(ref colors)).highlightedColor/*cast due to .constrained prefix*/).ToString(); obj2[6] = ", target graphic "; obj2[7] = (((Object)(object)((Selectable)donor).targetGraphic != (Object)null) ? ((Object)((Selectable)donor).targetGraphic).name : "none"); log2.LogInfo((object)string.Concat(obj2)); ManualLogSource log3 = RistPlugin.Log; string[] obj3 = new string[5] { "Rists tab: rune on '", ((Object)val2).name, "' at ", null, null }; rect = ((Graphic)val2).rectTransform.rect; obj3[3] = ((object)((Rect)(ref rect)).size/*cast due to .constrained prefix*/).ToString(); obj3[4] = ", gold from the button."; log3.LogInfo((object)string.Concat(obj3)); } private static Texture2D Algiz() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) float[][] array = new float[3][] { new float[4] { 0.5f, 0.94f, 0.5f, 0.08f }, new float[4] { 0.5f, 0.52f, 0.1f, 0.1f }, new float[4] { 0.5f, 0.52f, 0.9f, 0.1f } }; float num = 5.76f; Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Vector2 p = default(Vector2); for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { ((Vector2)(ref p))..ctor((float)j + 0.5f, (float)(127 - i) + 0.5f); float num2 = float.MaxValue; float[][] array2 = array; foreach (float[] array3 in array2) { float num3 = Distance(p, new Vector2(array3[0] * 128f, array3[1] * 128f), new Vector2(array3[2] * 128f, array3[3] * 128f)); if (num3 < num2) { num2 = num3; } } val.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(num - num2 + 0.5f))); } } val.Apply(); return val; } private static float Distance(Vector2 p, Vector2 a, Vector2 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Vector2 val = b - a; float num = Mathf.Clamp01(Vector2.Dot(p - a, val) / Mathf.Max(0.0001f, ((Vector2)(ref val)).sqrMagnitude)); return Vector2.Distance(p, a + val * num); } private static void Open() { if ((Object)(object)InventoryGui.instance != (Object)null) { InventoryGui.instance.Hide(); } RistPanel.Open(); } } internal static class Ledger { private static readonly Dictionary<string, RistRecord> _records = new Dictionary<string, RistRecord>(); private static bool _loaded; private static bool _dirty; private static float _nextFlush; private static bool _readFailed; private static bool _saidRefusingToWrite; private static bool _reconcileBlocked; private static string _reconcileWhy = ""; private static string LedgerPath => Path.Combine(Paths.ConfigPath, "rist-ledger.txt"); internal static RistRecord For(string owner) { Load(); if (string.IsNullOrEmpty(owner)) { return null; } if (!_records.TryGetValue(owner, out var value)) { value = new RistRecord { Owner = owner }; _records[owner] = value; _dirty = true; } return value; } internal static void Touch() { _dirty = true; } private static void Load() { if (_loaded) { return; } _loaded = true; if (File.Exists(LedgerPath)) { try { int num = 0; string[] array = File.ReadAllLines(LedgerPath); foreach (string text in array) { if (text.Trim().Length != 0) { RistRe