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 IceSniperStaff v0.9.0
plugins\SniperStaff.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SniperStaff")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SniperStaff")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.9.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.0.0")] namespace SniperStaff; [BepInPlugin("dots.icesniperstaff", "Ice Sniper Staff", "0.9.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SniperStaffPlugin : BaseUnityPlugin { public const string PluginGUID = "dots.icesniperstaff"; public const string WizardryGUID = "Therzie.Wizardry"; public const string PluginName = "Ice Sniper Staff"; public const string PluginVersion = "0.9.0"; internal static ManualLogSource Log; private readonly Harmony _harmony = new Harmony("dots.icesniperstaff"); internal const string NewPrefab = "RuneStaffSniper"; internal const string VanillaReference = "CrossbowArbalest"; private const string BundleResource = "SniperStaff.Assets.bundles.sniperstaff"; private const string BundleName = "sniperstaff"; internal const string CustomProjectile = "RuneStaffSniper_projectile"; private const string ReloadClipName = "reload_sfx"; private const string IconName = "icon_icestaff"; internal static GameObject StaffProjectile; internal static AudioClip ReloadClip; private static readonly string[] ProjectileCandidates = new string[3] { "RuneStaffSniper_projectile", "staff_iceshard_projectile", "staff_fireball_projectile" }; private static readonly string[] ProjectileBaseCandidates = new string[3] { "staff_iceshard_projectile", "DvergerStaffIce_projectile", "staff_fireball_projectile" }; internal static ConfigEntry<float> Damage; internal static ConfigEntry<float> PierceDamage; internal static ConfigEntry<float> FrostDamage; internal static ConfigEntry<float> PierceDamagePerLevel; internal static ConfigEntry<float> FrostDamagePerLevel; internal static ConfigEntry<float> Velocity; internal static ConfigEntry<float> Accuracy; internal static ConfigEntry<float> EitrCost; internal static ConfigEntry<float> ReloadTime; internal static ConfigEntry<float> ReloadVolume; internal static ConfigEntry<bool> SilenceReloadAnim; internal static ConfigEntry<bool> FlatShot; internal static ConfigEntry<bool> NoExplosion; internal static ConfigEntry<float> ProjectileScale; private static readonly Dictionary<string, Color> MaterialColors = new Dictionary<string, Color> { { "Mat_Wood", new Color(0.45f, 0.3f, 0.16f, 1f) }, { "Mat_Metal", new Color(0.55f, 0.57f, 0.6f, 1f) } }; private static readonly HashSet<string> PreserveMaterials = new HashSet<string> { "Mat_Crystal" }; private AssetBundle _bundle; private static bool _projectileReady; private static bool _soundsApplied; private static readonly string[] FireSfxCandidates = new string[3] { "fx_iceshard_launch", "sfx_dverger_ice_projectile_start", "sfx_icestaff_start" }; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; BindConfig(); PrefabManager.OnVanillaPrefabsAvailable += RegisterStaff; _harmony.PatchAll(); Log.LogInfo((object)"Ice Sniper Staff v0.9.0 loaded."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } if ((Object)(object)_bundle != (Object)null) { _bundle.Unload(false); } } private void BindConfig() { Damage = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "DamageMultiplier", 1f, "Damage multiplier applied at fire time (1 = use raw values below)."); PierceDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "PierceDamage", 70f, "Pierce damage per shot (quality 1)."); FrostDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "FrostDamage", 170f, "Frost damage per shot (quality 1)."); PierceDamagePerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "PierceDamagePerLevel", 10f, "Extra pierce damage gained per upgrade level."); FrostDamagePerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "FrostDamagePerLevel", 15f, "Extra frost damage gained per upgrade level."); Velocity = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "Velocity", 240f, "Projectile speed at fire time (sniper = fast)."); Accuracy = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "Accuracy", 0f, "Aim spread in degrees."); EitrCost = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "EitrCost", 40f, "Eitr cost per shot."); ReloadTime = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "ReloadTime", 2f, "Crossbow-style reload/draw time in seconds."); ReloadVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "ReloadVolume", 1f, "Reload sound volume (0 = silent, 1 = full)."); SilenceReloadAnim = ((BaseUnityPlugin)this).Config.Bind<bool>("Sniper", "SilenceReloadAnim", true, "Clear the reload animation to silence the vanilla crossbow reload sound. May also remove the visible reload animation."); FlatShot = ((BaseUnityPlugin)this).Config.Bind<bool>("Sniper", "FlatShot", true, "Remove projectile gravity for a flat line."); NoExplosion = ((BaseUnityPlugin)this).Config.Bind<bool>("Sniper", "NoExplosion", true, "Strip the AoE so it's a clean single-target dart."); ProjectileScale = ((BaseUnityPlugin)this).Config.Bind<float>("Sniper", "ProjectileScale", 1.4f, "Visual size multiplier for the projectile (1 = vanilla)."); } private void RegisterStaff() { //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Expected O, but got Unknown try { _bundle = AssetUtils.LoadAssetBundleFromResources("sniperstaff", Assembly.GetExecutingAssembly()); if ((Object)(object)_bundle == (Object)null) { Log.LogError((object)"AssetBundle 'sniperstaff' not found as embedded resource 'SniperStaff.Assets.bundles.sniperstaff'."); return; } GameObject val = _bundle.LoadAsset<GameObject>("RuneStaffSniper"); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Prefab 'RuneStaffSniper' not found inside bundle 'sniperstaff'."); return; } ReloadClip = _bundle.LoadAsset<AudioClip>("reload_sfx"); if ((Object)(object)ReloadClip == (Object)null) { Log.LogError((object)"Reload clip 'reload_sfx' NOT found in bundle 'sniperstaff'. Check the AssetBundle assignment in Unity and the clip name."); } else { Log.LogInfo((object)("Reload clip 'reload_sfx' loaded, length=" + ReloadClip.length + "s.")); } Shader val2 = Shader.Find("Standard"); Log.LogDebug((object)("Game Shader.Find(\"Standard\") = " + (((Object)(object)val2 == (Object)null) ? "NULL" : (((Object)val2).name + " supported=" + val2.isSupported)))); GameObject prefab = PrefabManager.Instance.GetPrefab("CrossbowArbalest"); if ((Object)(object)prefab == (Object)null) { Log.LogError((object)"Vanilla reference 'CrossbowArbalest' not found! Check the exact prefab name in LogOutput.log."); } MeshRenderer val3 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<MeshRenderer>(true) : null); Shader val4 = (((Object)(object)val3 != (Object)null && (Object)(object)((Renderer)val3).sharedMaterial != (Object)null) ? ((Renderer)val3).sharedMaterial.shader : null); Log.LogDebug((object)("Vanilla mesh shader = " + (((Object)(object)val4 == (Object)null) ? "NULL" : (((Object)val4).name + " supported=" + val4.isSupported)))); FixMaterials(val, val2, val4); ItemConfig val5 = BuildRecipe(); ConfigureWeapon(val, prefab); Sprite val6 = _bundle.LoadAsset<Sprite>("icon_icestaff"); if ((Object)(object)val6 != (Object)null) { Log.LogInfo((object)"Custom icon 'icon_icestaff' loaded from bundle."); } else { Log.LogWarning((object)"Custom icon 'icon_icestaff' NOT found in bundle; rendering a fallback. Check the sprite's Texture Type = Sprite and its AssetBundle assignment in Unity."); val6 = RenderManager.Instance.Render(val, RenderManager.IsometricRotation); } if ((Object)(object)val6 != (Object)null) { val5.Icon = val6; } else { Log.LogWarning((object)"No icon available (bundle sprite missing and render returned null)."); } ItemManager.Instance.AddItem(new CustomItem(val, true, val5)); AddLocalization(); Log.LogInfo((object)"Registered RuneStaffSniper from bundle."); } catch (Exception ex) { Log.LogError((object)("RegisterStaff failed: " + ex)); } finally { PrefabManager.OnVanillaPrefabsAvailable -= RegisterStaff; } } private static ItemConfig BuildRecipe() { //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_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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) //IL_012f: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_002c: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0085: 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) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown string craftingStation; int minStationLevel; RequirementConfig[] requirements; if (Chainloader.PluginInfos.ContainsKey("Therzie.Wizardry")) { craftingStation = "WizardTable_TW"; minStationLevel = 4; requirements = (RequirementConfig[])(object)new RequirementConfig[4] { new RequirementConfig { Item = "EnchantedWoodMountain_TW", Amount = 20, AmountPerLevel = 0, Recover = true }, new RequirementConfig { Item = "Staffcore_Mountain_TW", Amount = 3, AmountPerLevel = 0, Recover = true }, new RequirementConfig { Item = "Silver", Amount = 5, AmountPerLevel = 0, Recover = true }, new RequirementConfig { Item = "ArcaneScroll_Mountain_TW", Amount = 0, AmountPerLevel = 2, Recover = false } }; Log.LogDebug((object)"Recipe: Wizardry detected -> WizardTable_TW lvl 4, scroll upgrades."); } else { craftingStation = "forge"; minStationLevel = 1; requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig { Item = "YggdrasilWood", Amount = 20, AmountPerLevel = 10, Recover = true }, new RequirementConfig { Item = "Eitr", Amount = 16, AmountPerLevel = 8, Recover = true }, new RequirementConfig { Item = "Crystal", Amount = 6, AmountPerLevel = 3, Recover = true } }; Log.LogWarning((object)"Recipe: Wizardry NOT installed -> using vanilla fallback recipe at forge."); } return new ItemConfig { Name = "$item_runestaff_sniper", Description = "$item_runestaff_sniper_desc", CraftingStation = craftingStation, MinStationLevel = minStationLevel, Requirements = requirements }; } private void ConfigureWeapon(GameObject prefab, GameObject vanilla) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || (Object)(object)vanilla == (Object)null) { Log.LogWarning((object)("Could not copy weapon data: drop=" + ((Object)(object)component != (Object)null) + " vanilla=" + ((Object)(object)vanilla != (Object)null))); return; } SharedData shared = vanilla.GetComponent<ItemDrop>().m_itemData.m_shared; SharedData shared2 = component.m_itemData.m_shared; shared2.m_itemType = shared.m_itemType; shared2.m_animationState = shared.m_animationState; shared2.m_attack = shared.m_attack.Clone(); shared2.m_secondaryAttack = shared.m_secondaryAttack.Clone(); shared2.m_skillType = (SkillType)9; shared2.m_attack.m_reloadTime = ReloadTime.Value; shared2.m_attack.m_reloadStaminaDrain = 0f; shared2.m_attack.m_reloadEitrDrain = 0f; Log.LogDebug((object)("Reload animation (original) = '" + shared2.m_attack.m_reloadAnimation + "'")); if (SilenceReloadAnim.Value) { shared2.m_attack.m_reloadAnimation = ""; Log.LogDebug((object)"SilenceReloadAnim: cleared m_reloadAnimation."); } DamageTypes damages = shared.m_damages; damages.m_damage = 0f; damages.m_blunt = 0f; damages.m_slash = 0f; damages.m_pierce = PierceDamage.Value; damages.m_chop = 0f; damages.m_pickaxe = 0f; damages.m_fire = 0f; damages.m_frost = FrostDamage.Value; damages.m_lightning = 0f; damages.m_poison = 0f; damages.m_spirit = 0f; shared2.m_damages = damages; DamageTypes damagesPerLevel = shared.m_damagesPerLevel; damagesPerLevel.m_damage = 0f; damagesPerLevel.m_blunt = 0f; damagesPerLevel.m_slash = 0f; damagesPerLevel.m_pierce = PierceDamagePerLevel.Value; damagesPerLevel.m_chop = 0f; damagesPerLevel.m_pickaxe = 0f; damagesPerLevel.m_fire = 0f; damagesPerLevel.m_frost = FrostDamagePerLevel.Value; damagesPerLevel.m_lightning = 0f; damagesPerLevel.m_poison = 0f; damagesPerLevel.m_spirit = 0f; shared2.m_damagesPerLevel = damagesPerLevel; shared2.m_attackForce = shared.m_attackForce; shared2.m_useDurability = shared.m_useDurability; shared2.m_maxDurability = shared.m_maxDurability; shared2.m_destroyBroken = shared.m_destroyBroken; shared2.m_equipDuration = shared.m_equipDuration; shared2.m_aiAttackRange = shared.m_aiAttackRange; shared2.m_ammoType = ""; shared2.m_attack.m_attackEitr = EitrCost.Value; shared2.m_attack.m_attackStamina = 0f; shared2.m_attack.m_drawStaminaDrain = 0f; StaffProjectile = ResolveProjectile(); if ((Object)(object)StaffProjectile != (Object)null) { shared2.m_attack.m_attackProjectile = StaffProjectile; } else { Log.LogError((object)"No projectile candidate found in ZNetScene! Staff cannot fire. Check candidate names against LogOutput / prefab list."); } shared2.m_name = "$item_runestaff_sniper"; shared2.m_description = "$item_runestaff_sniper_desc"; shared2.m_maxQuality = 4; shared2.m_attack.m_projectiles = 1; shared2.m_attack.m_projectileBursts = 1; shared2.m_attack.m_burstInterval = 0f; Log.LogDebug((object)("Setup -> attackAnim='" + shared2.m_attack.m_attackAnimation + "', skill=" + ((object)Unsafe.As<SkillType, SkillType>(ref shared2.m_skillType)/*cast due to .constrained prefix*/).ToString() + ", animState=" + ((object)Unsafe.As<AnimationState, AnimationState>(ref shared2.m_animationState)/*cast due to .constrained prefix*/).ToString() + ", ammoType='" + shared2.m_ammoType + "', attackEitr=" + shared2.m_attack.m_attackEitr + ", reloadTime=" + shared2.m_attack.m_reloadTime + ", projectile=" + (((Object)(object)shared2.m_attack.m_attackProjectile != (Object)null) ? ((Object)shared2.m_attack.m_attackProjectile).name : "NULL"))); Log.LogDebug((object)("VERIFY damage -> pierce=" + shared2.m_damages.m_pierce + " frost=" + shared2.m_damages.m_frost + " | perLevel pierce=" + shared2.m_damagesPerLevel.m_pierce + " frost=" + shared2.m_damagesPerLevel.m_frost + " | maxQuality=" + shared2.m_maxQuality + " (multiplier at fire=" + Damage.Value + ")")); } internal static void EnsureProjectileReady() { if (!_projectileReady && !((Object)(object)ZNetScene.instance == (Object)null)) { BuildCustomProjectile(); StaffProjectile = ResolveProjectile(); if ((Object)(object)StaffProjectile != (Object)null && ((Object)StaffProjectile).name == "RuneStaffSniper_projectile") { _projectileReady = true; Log.LogDebug((object)"EnsureProjectileReady: custom projectile is live."); } else { Log.LogWarning((object)("EnsureProjectileReady: still using fallback '" + (((Object)(object)StaffProjectile != (Object)null) ? ((Object)StaffProjectile).name : "NULL") + "'.")); } ApplyFireSound(); } } private static void ApplyFireSound() { if (_soundsApplied) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab("RuneStaffSniper"); if ((Object)(object)prefab == (Object)null) { return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null)) { SharedData shared = component.m_itemData.m_shared; GameObject val = FirstExisting(FireSfxCandidates); if ((Object)(object)val != (Object)null) { SetEffect(shared.m_attack.m_startEffect, val); SetEffect(shared.m_attack.m_triggerEffect, val); Log.LogDebug((object)("ApplyFireSound: fire sound -> " + ((Object)val).name)); } else { Log.LogWarning((object)"ApplyFireSound: no fire sfx candidate found; keeping vanilla."); } _soundsApplied = true; } } private static GameObject FirstExisting(string[] names) { foreach (string text in names) { GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab != (Object)null) { return prefab; } } return null; } private static void SetEffect(EffectList list, GameObject prefab) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (list != null && !((Object)(object)prefab == (Object)null)) { list.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { new EffectData { m_prefab = prefab, m_enabled = true, m_variant = -1 } }; } } private static void BuildCustomProjectile() { //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)PrefabManager.Instance.GetPrefab("RuneStaffSniper_projectile") != (Object)null) { return; } GameObject val = null; string text = null; string[] projectileBaseCandidates = ProjectileBaseCandidates; foreach (string text2 in projectileBaseCandidates) { GameObject prefab = PrefabManager.Instance.GetPrefab(text2); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<Projectile>() != (Object)null) { val = prefab; text = text2; break; } Log.LogDebug((object)("BuildCustomProjectile: base candidate '" + text2 + "' -> " + (((Object)(object)prefab == (Object)null) ? "not found" : "no Projectile component"))); } if ((Object)(object)val == (Object)null) { Log.LogError((object)"BuildCustomProjectile: no usable base projectile found; staff will use fallback."); return; } Log.LogDebug((object)("BuildCustomProjectile: cloning base '" + text + "'.")); GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("RuneStaffSniper_projectile", val); if ((Object)(object)val2 == (Object)null) { Log.LogError((object)"BuildCustomProjectile: CreateClonedPrefab returned null."); return; } float num = Mathf.Max(0.1f, ProjectileScale.Value); if (Mathf.Abs(num - 1f) > 0.001f) { foreach (Transform item in val2.transform) { Transform val3 = item; val3.localScale *= num; } } Projectile component = val2.GetComponent<Projectile>(); if ((Object)(object)component != (Object)null) { ApplyProjectilePhysics(component); if (NoExplosion.Value) { StripSpawnOnHit(component); } } else { Log.LogWarning((object)"BuildCustomProjectile: clone has no Projectile component?!"); } Log.LogDebug((object)("BuildCustomProjectile: created 'RuneStaffSniper_projectile' from base, gravity=" + (((Object)(object)component != (Object)null) ? component.m_gravity.ToString() : "n/a") + ", noExplosion=" + NoExplosion.Value)); } internal static void ApplyProjectilePhysics(Projectile proj) { if (!((Object)(object)proj == (Object)null)) { if (FlatShot.Value) { proj.m_gravity = 0f; } proj.m_rayRadius = Mathf.Max(proj.m_rayRadius, 0.2f); } } private static void StripSpawnOnHit(Projectile proj) { FieldInfo[] fields = typeof(Projectile).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (fieldInfo.Name.IndexOf("spawnOnHit", StringComparison.OrdinalIgnoreCase) < 0) { continue; } try { if (typeof(GameObject).IsAssignableFrom(fieldInfo.FieldType)) { fieldInfo.SetValue(proj, null); } else if (typeof(IList).IsAssignableFrom(fieldInfo.FieldType) && fieldInfo.GetValue(proj) is IList list) { list.Clear(); } Log.LogDebug((object)("StripSpawnOnHit: cleared field '" + fieldInfo.Name + "'.")); } catch (Exception ex) { Log.LogWarning((object)("StripSpawnOnHit: could not clear '" + fieldInfo.Name + "': " + ex.Message)); } } } private static GameObject ResolveProjectile() { string[] projectileCandidates = ProjectileCandidates; foreach (string text in projectileCandidates) { GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<Projectile>() != (Object)null) { Log.LogDebug((object)("ResolveProjectile: using '" + text + "'.")); return prefab; } } return null; } private static void FixMaterials(GameObject root, Shader gameStandard, Shader vanillaShader) { //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) Shader val = null; val = (((Object)(object)gameStandard != (Object)null && gameStandard.isSupported) ? gameStandard : ((!((Object)(object)vanillaShader != (Object)null) || !vanillaShader.isSupported) ? Shader.Find("Custom/Creature") : vanillaShader)); if ((Object)(object)val == (Object)null) { Log.LogError((object)"FixMaterials: no usable shader found; staff will render pink/white."); return; } Log.LogDebug((object)("FixMaterials: using shader '" + ((Object)val).name + "'.")); int num = 0; Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { Material[] sharedMaterials = val2.sharedMaterials; foreach (Material val3 in sharedMaterials) { if ((Object)(object)val3 == (Object)null) { continue; } val3.shader = val; if (PreserveMaterials.Contains(((Object)val3).name)) { num++; continue; } if (!MaterialColors.TryGetValue(((Object)val3).name, out var value)) { ((Color)(ref value))..ctor(0.7f, 0.7f, 0.7f, 1f); } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", value); } if (val3.HasProperty("_MainColor")) { val3.SetColor("_MainColor", value); } if (val3.HasProperty("_Glossiness")) { val3.SetFloat("_Glossiness", 0.2f); } if (val3.HasProperty("_Smoothness")) { val3.SetFloat("_Smoothness", 0.2f); } if (val3.HasProperty("_Metallic")) { val3.SetFloat("_Metallic", 0f); } num++; } } Log.LogDebug((object)("FixMaterials: repaired " + num + " materials (preserved color on: " + string.Join(", ", PreserveMaterials) + ").")); } private void AddLocalization() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "item_runestaff_sniper", "Ice Sniper Staff" }, { "item_runestaff_sniper_desc", "A focusing rune mounted on a crossbow-stock. Draws like an arbalest, looses a single ice bolt in a dead-straight line. Slow to load, devastating on a hit." } }); } internal static bool IsSniperWeapon(ItemData weapon) { return weapon != null && (Object)(object)weapon.m_dropPrefab != (Object)null && ((Object)weapon.m_dropPrefab).name == "RuneStaffSniper"; } } [HarmonyPatch(typeof(DungeonDB), "Start")] internal static class ProjectileWarmupPatch { private static void Postfix() { try { SniperStaffPlugin.EnsureProjectileReady(); } catch (Exception ex) { SniperStaffPlugin.Log.LogWarning((object)("Warmup failed (will retry on fire): " + ex.Message)); } } } [HarmonyPatch(typeof(Attack), "FireProjectileBurst")] internal static class AttackFirePatch { private static void Prefix(Attack __instance) { if (__instance != null && __instance.m_weapon != null && SniperStaffPlugin.IsSniperWeapon(__instance.m_weapon)) { Attack attack = __instance.m_weapon.m_shared.m_attack; if ((Object)(object)SniperStaffPlugin.StaffProjectile == (Object)null || ((Object)SniperStaffPlugin.StaffProjectile).name != "RuneStaffSniper_projectile") { SniperStaffPlugin.EnsureProjectileReady(); } if ((Object)(object)SniperStaffPlugin.StaffProjectile != (Object)null) { attack.m_attackProjectile = SniperStaffPlugin.StaffProjectile; } float value = SniperStaffPlugin.Velocity.Value; float value2 = SniperStaffPlugin.Accuracy.Value; __instance.m_projectileVel = value; __instance.m_projectileVelMin = value; __instance.m_projectileAccuracy = value2; __instance.m_projectileAccuracyMin = value2; __instance.m_damageMultiplier = SniperStaffPlugin.Damage.Value; if (SniperStaffPlugin.FlatShot.Value && (Object)(object)__instance.m_attackProjectile != (Object)null) { Projectile component = __instance.m_attackProjectile.GetComponent<Projectile>(); SniperStaffPlugin.ApplyProjectilePhysics(component); } } } } [HarmonyPatch(typeof(Attack), "HaveAmmo")] internal static class AmmoBypassPatch { private static void Postfix(Attack __instance, ref bool __result) { if (__instance != null && __instance.m_weapon != null && SniperStaffPlugin.IsSniperWeapon(__instance.m_weapon)) { __result = true; } } } [HarmonyPatch(typeof(Player), "UpdateActionQueue")] internal static class ReloadSoundPatch { private static bool _wasReloading; private static void Postfix(Player __instance) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)SniperStaffPlugin.ReloadClip == (Object)null)) { ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon(); bool flag = SniperStaffPlugin.IsSniperWeapon(currentWeapon); string text = default(string); float num = default(float); MinorActionData val = default(MinorActionData); __instance.GetActionProgress(ref text, ref num, ref val); bool flag2 = flag && val != null && (int)val.m_type == 2; if (_wasReloading && !flag2 && flag && ((Humanoid)__instance).IsWeaponLoaded()) { PlayReloadSound(((Component)__instance).transform.position); } _wasReloading = flag2; } } private static void PlayReloadSound(Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SniperReloadSfx"); val.transform.position = pos; AudioSource val2 = val.AddComponent<AudioSource>(); val2.clip = SniperStaffPlugin.ReloadClip; val2.volume = Mathf.Clamp01(SniperStaffPlugin.ReloadVolume.Value); val2.spatialBlend = 1f; val2.minDistance = 3f; val2.maxDistance = 30f; val2.Play(); Object.Destroy((Object)(object)val, SniperStaffPlugin.ReloadClip.length + 0.1f); } }