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 RidingCrop v1.0.0
RidingCrop/RidingCrop.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("kydldev")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Adds a family of seven craftable, bleeding Riding Crop weapons to Valheim.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RidingCrop")] [assembly: AssemblyTitle("RidingCrop")] [assembly: AssemblyVersion("1.0.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 RidingCrop { [BepInPlugin("com.kydldev.RidingCrop", "RidingCrop", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class RidingCropPlugin : BaseUnityPlugin { private sealed class Tier { public readonly string PrefabName; public readonly string DisplayName; public readonly string Description; public readonly string AlbedoName; public readonly string Station; public readonly int StationLevel; public readonly RequirementConfig[] Requirements; public Tier(string prefabName, string displayName, string description, string albedoName, string station, int stationLevel, params RequirementConfig[] requirements) { PrefabName = prefabName; DisplayName = displayName; Description = description; AlbedoName = albedoName; Station = station; StationLevel = stationLevel; Requirements = requirements; } } public const string PluginGuid = "com.kydldev.RidingCrop"; public const string PluginName = "RidingCrop"; public const string PluginVersion = "1.0.0"; private const string VanillaBasePrefab = "Club"; private const string BundleFileName = "ridingcrop"; private const string SkillIdentifier = "com.kydldev.ridingcrop.ridingcrop"; private const string SkillName = "RidingCrop"; private const string WhooshClipKey = "whoosh"; private const string SlapClipKey = "slap"; private static readonly Tier[] Tiers = new Tier[7] { new Tier("RidingCrop", "Do I boar you?", "A slim leather-wrapped riding crop with a gold-capped handle. It stings.", "crop_Albedo", CraftingStations.Workbench, 1, Req("LeatherScraps", 10), Req("Resin", 2), Req("Wood", 5)), new Tier("RidingCrop_V1", "Dear, oh deer!", "A scarlet-wrapped riding crop with black fittings and a white-bound collar. Hits harder than the crop before it.", "crop_Albedo_V1", CraftingStations.Workbench, 2, Req("DeerHide", 10), Req("Bronze", 2), Req("FineWood", 5)), new Tier("RidingCrop_V3", "Bear with me!", "A black riding crop with red fittings and a red-bound collar. Hits harder than the crop before it.", "crop_Albedo_V3", CraftingStations.Forge, 1, Req("BjornHide", 10), Req("SurtlingCore", 2), Req("RoundLog", 5)), new Tier("RidingCrop_V4", "Howl yeah!", "A white riding crop with black fittings and a black-bound collar. Hits harder than the crop before it.", "crop_Albedo_V4", CraftingStations.Forge, 2, Req("WolfPelt", 10), Req("Obsidian", 2), Req("FineWood", 5)), new Tier("RidingCrop_V6", "Loxy Poxy", "A burnt-orange riding crop with black fittings and a black-bound collar. Hits harder than the crop before it.", "crop_Albedo_V6", CraftingStations.Forge, 3, Req("LoxPelt", 10), Req("Tar", 2), Req("ElderBark", 5)), new Tier("RidingCrop_V2", "Askvin worthy", "A deep green riding crop with black fittings and a black-bound collar. Hits harder than the crop before it.", "crop_Albedo_V2", CraftingStations.BlackForge, 1, Req("AskHide", 10), Req("CharredBone", 2), Req("Blackwood", 5)), new Tier("RidingCrop_V5", "Seal the deal!", "A weathered, bone-grey riding crop with brown fittings and a brown-bound collar. The finest of the family.", "crop_Albedo_V5", CraftingStations.BlackForge, 2, Req("MooseHide", 10), Req("SealHide", 2), Req("Frostwood", 5)) }; private const float RotationX = 270f; private const float RotationY = 180f; private const float RotationZ = 0f; private const float GripOffset = 0.18f; private const float ModelScale = 1f; private const float IconTiltDegrees = 45f; private const float SoundGain = 1.5f; private const float BaseBluntDamage = 20f; private const float BaseBleedDamagePerSecond = 10f; private const float BleedDurationSeconds = 5f; private const float DamageGrowthPerTier = 0.4f; private const float BleedGrowthPerTier = 0.25f; private const float ParryBonus = 2f; private const float LastChainDamageMultiplier = 2f; private static readonly float[] Stagger = new float[7] { 12f, 25f, 35f, 55f, 95f, 125f, 150f }; private static readonly float[] Knockback = new float[7] { 30f, 60f, 80f, 100f, 100f, 100f, 100f }; private static readonly float[] Stamina = new float[7] { 6f, 8f, 10f, 12f, 14f, 16f, 18f }; private static readonly float[] BlockArmor = new float[7] { 3f, 12f, 21f, 30f, 39f, 57f, 66f }; private static readonly float[] BlockForce = new float[7] { 20f, 30f, 30f, 30f, 30f, 30f, 30f }; private const float BaseDurability = 200f; private const float DurabilityStepPerTier = 50f; private const float UpgradeBluntFractionOfBase = 0.3f; private const float UpgradeDurabilityFractionOfBase = 0.2f; private const int MaxQuality = 4; internal static RidingCropPlugin Instance; internal static GameObject SlapPrefab; internal static GameObject WhooshPrefab; private ConfigEntry<float> _whooshVolume; private ConfigEntry<float> _slapVolume; private ConfigEntry<bool> _enabled; private ConfigEntry<bool> _debugLogging; private ConfigEntry<bool> _normalizeSlap; private ConfigEntry<bool> _replaceVanillaSounds; private readonly List<Transform> _visuals = new List<Transform>(); private readonly List<CustomItem> _items = new List<CustomItem>(); private Mesh _mesh; private readonly Dictionary<string, Texture2D> _albedos = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase); private Texture2D _normal; private Texture2D _metalGloss; private AudioClip _whooshClip; private AudioClip _slapClip; private bool _soundsReady; private GameObject _whooshPrefab; private GameObject _slapPrefab; private SkillConfig _skillConfig; private SkillType _skillType; private const float LimiterKnee = 0.7f; internal static bool DebugLogging { get { if ((Object)(object)Instance != (Object)null && Instance._debugLogging != null) { return Instance._debugLogging.Value; } return false; } } private static RequirementConfig Req(string item, int amount) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown return new RequirementConfig(item, amount, Mathf.Max(1, (amount + 1) / 2), true); } internal static void Dbg(string message) { if (DebugLogging) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[debug] " + message)); } } private void Awake() { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown Instance = this; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. true = the mod adds the Riding Crops, their skill and their sounds. false = the mod does nothing at all (no items, no skill, no patches). Needs a game restart. Note: while it is off, Riding Crop items are unknown to the game, so keep it on for any world or character that uses them, and use the same value as the server."); _debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "true = write extra detail to the BepInEx log (asset bundle contents, every crop's stats, recipes and stations, sound setup, and every whoosh / slap / bleed event). Can be changed while the game runs. For troubleshooting only."); if (!_enabled.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RidingCrop 1.0.0 is disabled (General > Enabled = false in " + ((BaseUnityPlugin)this).Config.ConfigFilePath + "). Nothing was added.")); return; } _whooshVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "WhooshVolume", 1f, new ConfigDescription("Volume of the swing (whoosh) sound. Needs a game restart.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _slapVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "SlapVolume", 1f, new ConfigDescription("Volume of the slap sound when the crop hits something. Needs a game restart.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _replaceVanillaSounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Sound", "ReplaceVanillaSounds", true, "true = the crops only make their own swing/hit sounds. false = the Club's sounds play as well. Needs a game restart."); _normalizeSlap = ((BaseUnityPlugin)this).Config.Bind<bool>("Sound", "SlapNormalize", true, "true = when the game starts, cut the quiet lead-in from the start of the slap sound so the impact is heard the moment you hit (the slap file has roughly 50-70 ms of build-up before the impact, which made it arrive late), and raise the sound to the loudest level its data allows. false = use the sound exactly as it is in the asset bundle. Needs a game restart."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("RidingCrop 1.0.0 loaded. Debug logging is " + (_debugLogging.Value ? "ON" : "OFF") + " (General > DebugLogging in " + ((BaseUnityPlugin)this).Config.ConfigFilePath + ").")); if (!LoadAssetBundle()) { ((BaseUnityPlugin)this).Logger.LogError((object)"Riding Crop was NOT added because its asset bundle could not be loaded."); return; } RegisterSkill(); Harmony.CreateAndPatchAll(typeof(RidingCropPlugin).Assembly, "com.kydldev.RidingCrop"); LogPatchStatus(); PrefabManager.OnVanillaPrefabsAvailable += AddRidingCrops; } private void LogPatchStatus() { try { MethodInfo methodInfo = AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null); int num = ((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null)?.Prefixes.Count((Patch p) => p.owner == "com.kydldev.RidingCrop") ?? 0; if (num > 0) { Dbg($"Harmony patch on EffectList.Create is installed ({num} prefix)."); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Harmony patch on EffectList.Create is NOT installed - the slap-once-per-swing handling and its debug lines will not work."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not check the Harmony patch status: " + ex.Message)); } } private bool LoadAssetBundle() { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "ridingcrop"); if (!File.Exists(text)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Asset bundle file not found: " + text + " (it must sit in the same folder as the DLL)")); return false; } AssetBundle val = AssetUtils.LoadAssetBundle(text); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Unity could not load the asset bundle " + text + ". Most common cause: it was built with a different Unity version than Valheim uses.")); return false; } try { _mesh = val.LoadAllAssets<Mesh>().FirstOrDefault(); Texture2D[] array = val.LoadAllAssets<Texture2D>(); Texture2D[] array2 = array; foreach (Texture2D val2 in array2) { if (((Object)val2).name.IndexOf("Albedo", StringComparison.OrdinalIgnoreCase) >= 0) { _albedos[((Object)val2).name] = val2; } } _normal = ((IEnumerable<Texture2D>)array).FirstOrDefault((Func<Texture2D, bool>)((Texture2D t) => ((Object)t).name.IndexOf("Normal", StringComparison.OrdinalIgnoreCase) >= 0)); _metalGloss = ((IEnumerable<Texture2D>)array).FirstOrDefault((Func<Texture2D, bool>)((Texture2D t) => ((Object)t).name.IndexOf("MetalGloss", StringComparison.OrdinalIgnoreCase) >= 0)); AudioClip[] source = val.LoadAllAssets<AudioClip>(); _whooshClip = ((IEnumerable<AudioClip>)source).FirstOrDefault((Func<AudioClip, bool>)((AudioClip c) => ((Object)c).name.IndexOf("whoosh", StringComparison.OrdinalIgnoreCase) >= 0)); _slapClip = ((IEnumerable<AudioClip>)source).FirstOrDefault((Func<AudioClip, bool>)((AudioClip c) => ((Object)c).name.IndexOf("slap", StringComparison.OrdinalIgnoreCase) >= 0)); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Exception while reading the asset bundle: {arg}"); } finally { val.Unload(false); } string[] obj = new string[8] { "Bundle contents -> mesh: ", null, null, null, null, null, null, null }; Mesh mesh = _mesh; obj[1] = ((mesh != null) ? ((Object)mesh).name : null) ?? "MISSING"; obj[2] = ", albedo textures: "; obj[3] = string.Join(", ", _albedos.Keys.OrderBy((string k) => k)); obj[4] = ", normal: "; Texture2D normal = _normal; obj[5] = ((normal != null) ? ((Object)normal).name : null) ?? "MISSING"; obj[6] = ", metal/gloss: "; Texture2D metalGloss = _metalGloss; obj[7] = ((metalGloss != null) ? ((Object)metalGloss).name : null) ?? "MISSING"; Dbg(string.Concat(obj)); Tier[] tiers = Tiers; foreach (Tier tier in tiers) { if (!_albedos.ContainsKey(tier.AlbedoName)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Texture '" + tier.AlbedoName + "' for '" + tier.PrefabName + "' is MISSING from the bundle (rebuild it in Unity: Valheim > Build Riding Crop Bundle). That crop will NOT be added.")); } } AudioClip whooshClip = _whooshClip; string obj2 = ((whooshClip != null) ? ((Object)whooshClip).name : null) ?? "MISSING"; AudioClip slapClip = _slapClip; Dbg("Bundle sounds -> whoosh: " + obj2 + ", slap: " + (((slapClip != null) ? ((Object)slapClip).name : null) ?? "MISSING")); if ((Object)(object)_whooshClip == (Object)null || (Object)(object)_slapClip == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"A sound clip is missing from the bundle (rebuild it in Unity: Valheim > Build Riding Crop Bundle). The crops will work, but without their own sound for the missing clip."); } if ((Object)(object)_mesh != (Object)null) { return _albedos.Count > 0; } return false; } private void AddRidingCrops() { PrefabManager.OnVanillaPrefabsAvailable -= AddRidingCrops; for (int i = 0; i < Tiers.Length; i++) { try { AddTier(Tiers[i], i); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not add '{Tiers[i].PrefabName}': {arg}"); } } ApplyAlignment(); if (_items.Count < Tiers.Length) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Riding Crop family INCOMPLETE: only {_items.Count} of {Tiers.Length} item(s) registered. See the errors above."); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Riding Crop family registered: {_items.Count} of {Tiers.Length} item(s)."); } } private void AddTier(Tier tier, int index) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //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_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Expected O, but got Unknown if (!_albedos.ContainsKey(tier.AlbedoName)) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Skipping '{tier.PrefabName}' (tier {index}): texture '{tier.AlbedoName}' is not in the asset bundle."); return; } ItemConfig val = new ItemConfig { Name = tier.DisplayName, Description = tier.Description, CraftingStation = tier.Station, MinStationLevel = tier.StationLevel, Requirements = tier.Requirements }; CustomItem val2 = new CustomItem(tier.PrefabName, "Club", val); if ((Object)(object)val2.ItemPrefab == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not clone vanilla prefab 'Club'. '" + tier.PrefabName + "' not added.")); return; } ApplyVisuals(val2.ItemPrefab, tier); Dbg($"'{tier.PrefabName}': station {tier.Station} level {tier.StationLevel} (quality 1), ingredients: " + string.Join(", ", tier.Requirements.Select((RequirementConfig r) => $"{r.Amount} {r.Item} (+{r.AmountPerLevel}/upgrade)"))); SharedData shared = val2.ItemDrop.m_itemData.m_shared; if ((int)_skillType != 0) { shared.m_skillType = _skillType; } SE_RidingCropBleed sE_RidingCropBleed = ApplyBalance(shared, tier, index); ApplySounds(shared); ItemManager.Instance.AddItem(val2); _items.Add(val2); GameObject val3 = null; try { val3 = CreateIconSource(val2.ItemPrefab) ?? val2.ItemPrefab; Sprite val4 = RenderManager.Instance.Render(new RenderRequest(val3) { Width = 128, Height = 128, Rotation = Quaternion.Euler(0f, 0f, 45f), UseCache = false }); if ((Object)(object)val4 != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { val4 }; if ((Object)(object)sE_RidingCropBleed != (Object)null) { ((StatusEffect)sE_RidingCropBleed).m_icon = val4; } if (_skillConfig != null && (Object)(object)_skillConfig.Icon == (Object)null) { _skillConfig.Icon = val4; } Dbg($"'{tier.PrefabName}' icon rendered (tilt {45f} degrees)."); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Icon render returned nothing; '" + tier.PrefabName + "' keeps the Club's icon.")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Icon render failed; '" + tier.PrefabName + "' keeps the Club's icon. " + ex.Message)); } finally { if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)val2.ItemPrefab) { Object.DestroyImmediate((Object)(object)val3); } } Dbg($"'{tier.DisplayName}' ({tier.PrefabName}) registered as tier {index}."); } private GameObject CreateIconSource(GameObject itemPrefab) { //IL_004a: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown MeshRenderer val = ((IEnumerable<MeshRenderer>)itemPrefab.GetComponentsInChildren<MeshRenderer>(true)).FirstOrDefault((Func<MeshRenderer, bool>)((MeshRenderer r) => ((Object)((Component)r).gameObject).name == "RidingCropVisual")); if ((Object)(object)val == (Object)null || (Object)(object)_mesh == (Object)null) { return null; } GameObject val2 = new GameObject("RidingCropIconSource"); val2.AddComponent<MeshFilter>().sharedMesh = _mesh; ((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = ((Renderer)val).sharedMaterial; return val2; } private SE_RidingCropBleed ApplyBalance(SharedData shared, Tier tier, int index) { //IL_004b: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_0074: 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_00a9: Expected O, but got Unknown float num = 20f * Mathf.Pow(1.4f, (float)index); float num2 = 10f * Mathf.Pow(1.25f, (float)index); float num3 = 200f + 50f * (float)index; float blunt = shared.m_damages.m_blunt; float num4 = 6f; shared.m_damages = new DamageTypes { m_blunt = num }; shared.m_damagesPerLevel = new DamageTypes { m_blunt = num4 }; shared.m_maxQuality = 4; float maxDurability = shared.m_maxDurability; float num5 = 40f; shared.m_maxDurability = num3; shared.m_durabilityPerLevel = num5; shared.m_secondaryAttack = new Attack(); shared.m_attack.m_attackStamina = Stamina[index]; shared.m_attack.m_staggerMultiplier = Stagger[index] / num; shared.m_attack.m_lastChainDamageMultiplier = 2f; shared.m_attackForce = Knockback[index]; shared.m_blockPower = BlockArmor[index]; shared.m_timedBlockBonus = 2f; shared.m_deflectionForce = BlockForce[index]; SE_RidingCropBleed sE_RidingCropBleed = null; if (num2 > 0f) { sE_RidingCropBleed = CreateBleed(tier, num2); if ((Object)(object)sE_RidingCropBleed != (Object)null) { shared.m_attackStatusEffect = (StatusEffect)(object)sE_RidingCropBleed; shared.m_attackStatusEffectChance = 1f; } } Dbg($"'{tier.PrefabName}': blunt {num:0.#} (Club {blunt:0.#}), bleed {num2:0.#}/s for {5f:0.#}s, " + $"+{num4:0.#} blunt per upgrade level (max quality {4}: {num + num4 * 3f:0.#}), " + $"+{num5:0.#} durability per upgrade level (max quality {4}: {num3 + num5 * 3f:0.#}), " + $"stagger {Stagger[index]:0.#}, knockback {Knockback[index]:0.#}, stamina {Stamina[index]:0.#}, block armor {BlockArmor[index]:0.#}, parry x{2f:0.#}, block force {BlockForce[index]:0.#}, durability {num3:0.#} (Club {maxDurability:0.#})."); return sE_RidingCropBleed; } private SE_RidingCropBleed CreateBleed(Tier tier, float damagePerSecond) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown try { SE_RidingCropBleed sE_RidingCropBleed = ScriptableObject.CreateInstance<SE_RidingCropBleed>(); ((Object)sE_RidingCropBleed).name = "SE_" + tier.PrefabName + "_Bleed"; sE_RidingCropBleed.Configure(damagePerSecond, 5f); ((StatusEffect)sE_RidingCropBleed).m_name = "Bleeding"; ((StatusEffect)sE_RidingCropBleed).m_tooltip = $"Bleeding: {damagePerSecond:0.#} damage per second for {5f:0.#} seconds."; if (!ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)sE_RidingCropBleed, false))) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Jotunn did not accept the bleed effect '" + ((Object)sE_RidingCropBleed).name + "'; '" + tier.PrefabName + "' will not make targets bleed.")); return null; } return sE_RidingCropBleed; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not create the bleed effect for '{tier.PrefabName}': {arg}"); return null; } } private void RegisterSkill() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0043: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected I4, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) try { _skillConfig = new SkillConfig { Identifier = "com.kydldev.ridingcrop.ridingcrop", Name = "RidingCrop", Description = "Skill with the riding crop. The higher it is, the harder the crop hits.", IncreaseStep = 1f }; _skillType = SkillManager.Instance.AddSkill(_skillConfig); Dbg(string.Format("Skill '{0}' registered (id {1}).", "RidingCrop", (int)_skillType)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not register the 'RidingCrop' skill; the crops will use the Clubs skill. " + ex.Message)); _skillConfig = null; _skillType = (SkillType)0; } } private void PrepareSounds(SharedData shared) { if (_soundsReady) { return; } _soundsReady = true; if ((Object)(object)_whooshClip == (Object)null && (Object)(object)_slapClip == (Object)null) { return; } LogEffects("m_startEffect", shared.m_startEffect); LogEffects("m_triggerEffect", shared.m_triggerEffect); LogEffects("m_hitEffect", shared.m_hitEffect); LogEffects("m_hitTerrainEffect", shared.m_hitTerrainEffect); GameObject val = FindSoundTemplate(shared); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"No vanilla sound prefab found to copy; the crops keep the Club's sounds."); return; } Dbg("Using vanilla sound prefab '" + ((Object)val).name + "' as the template for the crops' sounds."); if ((Object)(object)_whooshClip != (Object)null) { _whooshPrefab = CreateSoundPrefab("sfx_ridingcrop_whoosh", val, _whooshClip, _whooshVolume.Value, 1.5f, critical: false); } if ((Object)(object)_slapClip != (Object)null) { _slapPrefab = CreateSoundPrefab("sfx_ridingcrop_slap", val, _slapClip, _slapVolume.Value, 1.5f, critical: true); } WhooshPrefab = _whooshPrefab; SlapPrefab = _slapPrefab; } private void ApplySounds(SharedData shared) { PrepareSounds(shared); bool value = _replaceVanillaSounds.Value; if ((Object)(object)_whooshPrefab != (Object)null) { bool flag = HasSound(shared.m_startEffect); bool num = HasSound(shared.m_triggerEffect); if (value) { shared.m_startEffect = WithoutSounds(shared.m_startEffect); shared.m_triggerEffect = WithoutSounds(shared.m_triggerEffect); } if (flag) { shared.m_startEffect = With(shared.m_startEffect, _whooshPrefab); } if (num || !flag) { shared.m_triggerEffect = With(shared.m_triggerEffect, _whooshPrefab); } } if ((Object)(object)_slapPrefab != (Object)null) { if (value) { shared.m_hitEffect = WithoutSounds(shared.m_hitEffect); shared.m_hitTerrainEffect = WithoutSounds(shared.m_hitTerrainEffect); } shared.m_hitEffect = With(shared.m_hitEffect, _slapPrefab); shared.m_hitTerrainEffect = With(shared.m_hitTerrainEffect, _slapPrefab); } } private AudioClip PrepareClip(AudioClip source) { try { source.LoadAudioData(); int samples = source.samples; int channels = source.channels; float[] array = new float[samples * channels]; if (samples == 0 || !source.GetData(array, 0)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Slap clip '" + ((Object)source).name + "' could not be read; using it unchanged.")); return source; } float num = 0f; for (int i = 0; i < array.Length; i++) { float num2 = Mathf.Abs(array[i]); if (num2 > num) { num = num2; } } if (num < 0.0001f) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Slap clip '" + ((Object)source).name + "' is silent; using it unchanged.")); return source; } float num3 = 0.1f * num; int num4 = 0; for (int j = 0; j < array.Length; j++) { if (Mathf.Abs(array[j]) >= num3) { num4 = j / channels; break; } } int num5 = Mathf.Max(0, num4 - source.frequency / 200); int num6 = Mathf.Max(1, source.frequency * 3 / 1000); float num7 = Mathf.Max(1f, 0.98f / num); int num8 = samples - num5; float[] array2 = new float[num8 * channels]; for (int k = 0; k < num8; k++) { float num9 = ((k < num6) ? ((float)k / (float)num6) : 1f); for (int l = 0; l < channels; l++) { array2[k * channels + l] = Mathf.Clamp(array[(num5 + k) * channels + l] * num7 * num9, -1f, 1f); } } AudioClip val = AudioClip.Create(((Object)source).name + "_prepared", num8, channels, source.frequency, false); val.SetData(array2, 0); ((Object)val).hideFlags = (HideFlags)32; Dbg($"Slap clip '{((Object)source).name}': peak {num:0.000}, amplified x{num7:0.00}, removed {(float)num5 * 1000f / (float)source.frequency:0} ms of lead-in (length {source.length:0.000}s -> {val.length:0.000}s)."); return val; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Slap clip could not be prepared (" + ex.Message + "); using it unchanged.")); return source; } } private AudioClip ApplyGain(AudioClip source, float gain, string label) { if ((Object)(object)source == (Object)null || Mathf.Abs(gain - 1f) < 0.001f) { return source; } try { source.LoadAudioData(); int samples = source.samples; int channels = source.channels; float[] array = new float[samples * channels]; if (samples == 0 || !source.GetData(array, 0)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"{label}: clip '{((Object)source).name}' could not be read, so the x{gain:0.##} gain was NOT applied."); return source; } float num = 0f; float num2 = 0f; int num3 = 0; for (int i = 0; i < array.Length; i++) { float num4 = Mathf.Abs(array[i]); if (num4 > num) { num = num4; } float num5 = num4 * gain; if (num5 > 0.7f) { num3++; float num6 = 0.3f; num5 = 0.7f + num6 * (float)Math.Tanh((num5 - 0.7f) / num6); } if (num5 > num2) { num2 = num5; } array[i] = ((array[i] < 0f) ? (0f - num5) : num5); } AudioClip val = AudioClip.Create(((Object)source).name + "_gain", samples, channels, source.frequency, false); val.SetData(array, 0); ((Object)val).hideFlags = (HideFlags)32; Dbg($"{label}: gain x{gain:0.##} applied to '{((Object)source).name}', peak {num:0.000} -> {num2:0.000}" + ((num3 > 0) ? $", soft limiter touched {num3} of {array.Length} samples." : ", no limiting needed.")); return val; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"{label}: the x{gain:0.##} gain could not be applied ({ex.Message}); using the clip unchanged."); return source; } } private GameObject CreateSoundPrefab(string prefabName, GameObject template, AudioClip clip, float volume, float gain, bool critical) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) GameObject val = PrefabManager.Instance.CreateClonedPrefab(prefabName, template); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create sound prefab '" + prefabName + "'.")); return null; } ZSFX[] componentsInChildren = val.GetComponentsInChildren<ZSFX>(true); foreach (ZSFX val2 in componentsInChildren) { AudioSource component = ((Component)val2).GetComponent<AudioSource>(); Dbg($"Template of '{prefabName}': delay {val2.m_minDelay:0.###}-{val2.m_maxDelay:0.###}s, fade-in {val2.m_fadeInDuration:0.###}s, fade-out-on-awake {val2.m_fadeOutOnAwake}, " + $"volume {val2.m_minVol:0.##}-{val2.m_maxVol:0.##}, max concurrent {val2.m_maxConcurrentSources}" + (((Object)(object)component != (Object)null) ? string.Format(", spatialBlend {0:0.##}, distance {1:0.#}-{2:0.#}, rolloff {3}, mixer '{4}'.", component.spatialBlend, component.minDistance, component.maxDistance, component.rolloffMode, ((Object)(object)component.outputAudioMixerGroup != (Object)null) ? ((Object)component.outputAudioMixerGroup).name : "none") : ".")); } AudioClip val3 = clip; if (critical && _normalizeSlap.Value) { clip = PrepareClip(clip); } AudioClip val4 = clip; clip = ApplyGain(clip, gain, prefabName); if ((Object)(object)val4 != (Object)(object)val3 && (Object)(object)clip != (Object)(object)val4) { Object.Destroy((Object)(object)val4); } ZSFX[] componentsInChildren2 = val.GetComponentsInChildren<ZSFX>(true); componentsInChildren = componentsInChildren2; foreach (ZSFX val5 in componentsInChildren) { val5.m_audioClips = (AudioClip[])(object)new AudioClip[1] { clip }; val5.m_minVol = volume; val5.m_maxVol = volume; val5.m_hash = StringExtensionMethods.GetStableHashCode(prefabName); if (critical) { val5.m_maxConcurrentSources = 0; val5.m_minDelay = 0f; val5.m_maxDelay = 0f; val5.m_fadeInDuration = 0f; val5.m_fadeOutOnAwake = false; } } AudioSource[] componentsInChildren3 = val.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val6 in componentsInChildren3) { val6.clip = clip; if (critical) { val6.priority = 0; val6.spatialBlend = 0f; val6.loop = false; } } val.AddComponent<RidingCropSoundProbe>().Label = prefabName; PrefabManager.Instance.AddPrefab(val); Dbg($"Sound prefab '{prefabName}' created ({componentsInChildren2.Length} ZSFX, clip '{((Object)clip).name}', {clip.length:0.00}s)."); return val; } private GameObject FindSoundTemplate(SharedData shared) { List<GameObject> list = new List<GameObject>(); EffectList[] array = (EffectList[])(object)new EffectList[4] { shared.m_triggerEffect, shared.m_startEffect, shared.m_hitEffect, shared.m_hitTerrainEffect }; foreach (EffectList val in array) { if (val?.m_effectPrefabs == null) { continue; } EffectData[] effectPrefabs = val.m_effectPrefabs; foreach (EffectData val2 in effectPrefabs) { if ((Object)(object)val2?.m_prefab != (Object)null && IsSound(val2.m_prefab)) { list.Add(val2.m_prefab); } } } GameObject val3 = ((IEnumerable<GameObject>)list).FirstOrDefault((Func<GameObject, bool>)((GameObject c) => ((Object)c).name.StartsWith("sfx_", StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val3 != (Object)null) { return val3; } string[] array2 = new string[4] { "sfx_club_hit", "sfx_sword_hit", "sfx_sword_swing", "sfx_club_swing" }; foreach (string text in array2) { GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab != (Object)null && IsSound(prefab)) { return prefab; } } return list.FirstOrDefault(); } private static bool IsSound(GameObject prefab) { if ((Object)(object)prefab != (Object)null) { return (Object)(object)prefab.GetComponent<ZSFX>() != (Object)null; } return false; } private static bool HasSound(EffectList list) { if (list?.m_effectPrefabs != null) { return list.m_effectPrefabs.Any((EffectData e) => (Object)(object)e?.m_prefab != (Object)null && IsSound(e.m_prefab)); } return false; } private static EffectList WithoutSounds(EffectList list) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown List<EffectData> list2 = ((list?.m_effectPrefabs == null) ? new List<EffectData>() : list.m_effectPrefabs.Where((EffectData e) => e != null && (!((Object)(object)e.m_prefab != (Object)null) || !IsSound(e.m_prefab))).ToList()); return new EffectList { m_effectPrefabs = list2.ToArray() }; } private static EffectList With(EffectList list, GameObject prefab) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0065: 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_0077: Expected O, but got Unknown List<EffectData> list2 = ((list?.m_effectPrefabs == null) ? new List<EffectData>() : list.m_effectPrefabs.Where((EffectData e) => e != null).ToList()); list2.Add(new EffectData { m_prefab = prefab, m_enabled = true, m_variant = -1 }); return new EffectList { m_effectPrefabs = list2.ToArray() }; } private void LogEffects(string label, EffectList list) { string text = ((list?.m_effectPrefabs == null) ? "(none)" : string.Join(", ", from e in list.m_effectPrefabs where e != null select (((Object)(object)e.m_prefab != (Object)null) ? ((Object)e.m_prefab).name : "null") + (((Object)(object)e.m_prefab != (Object)null && IsSound(e.m_prefab)) ? "[sound]" : ""))); Dbg("Club " + label + ": " + text); } private void ApplyVisuals(GameObject prefab, Tier tier) { //IL_0097: 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) //IL_00b3: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_0170: Unknown result type (might be due to invalid IL or missing references) MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true); MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true); if (componentsInChildren.Length == 0 || componentsInChildren2.Length == 0) { ((BaseUnityPlugin)this).Logger.LogError((object)("The cloned prefab for '" + tier.PrefabName + "' has no MeshFilter/MeshRenderer to swap.")); return; } if (!_albedos.TryGetValue(tier.AlbedoName, out var value)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Texture '" + tier.AlbedoName + "' for '" + tier.PrefabName + "' is missing; visuals not applied.")); return; } Material val = new Material(((Renderer)componentsInChildren2[0]).sharedMaterial) { name = "RidingCropMaterial_" + tier.PrefabName }; val.mainTexture = (Texture)(object)value; SetTexture(val, "_BumpMap", _normal, "_NORMALMAP"); SetTexture(val, "_MetallicGlossMap", _metalGloss, "_METALLICGLOSSMAP"); MeshFilter[] array = componentsInChildren; foreach (MeshFilter val2 in array) { MeshRenderer component = ((Component)val2).GetComponent<MeshRenderer>(); GameObject val3 = new GameObject("RidingCropVisual"); val3.layer = ((Component)val2).gameObject.layer; val3.transform.SetParent(((Component)val2).transform, false); val3.AddComponent<MeshFilter>().sharedMesh = _mesh; MeshRenderer val4 = val3.AddComponent<MeshRenderer>(); ((Renderer)val4).sharedMaterials = (Material[])(object)new Material[1] { val }; if ((Object)(object)component != (Object)null) { ((Renderer)val4).shadowCastingMode = ((Renderer)component).shadowCastingMode; ((Renderer)val4).receiveShadows = ((Renderer)component).receiveShadows; Object.DestroyImmediate((Object)(object)component); } Object.DestroyImmediate((Object)(object)val2); _visuals.Add(val3.transform); } Dbg($"'{tier.PrefabName}': swapped {componentsInChildren.Length} mesh(es), texture '{((Object)value).name}'. Shader in use: {((Object)val.shader).name}"); } private void ApplyAlignment() { //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_0035: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) Quaternion val = Quaternion.Euler(270f, 180f, 0f); foreach (Transform visual in _visuals) { if (!((Object)(object)visual == (Object)null)) { visual.localRotation = val; visual.localScale = Vector3.one * 1f; visual.localPosition = val * new Vector3(0f, -0.18f, 0f); } } } internal static void Log(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } } private void SetTexture(Material material, string property, Texture2D texture, string keyword) { if (!material.HasProperty(property)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Shader '" + ((Object)material.shader).name + "' has no '" + property + "' slot; skipped.")); } else if ((Object)(object)texture == (Object)null) { material.SetTexture(property, (Texture)null); material.DisableKeyword(keyword); } else { material.SetTexture(property, (Texture)(object)texture); material.EnableKeyword(keyword); } } } [HarmonyPatch(typeof(EffectList), "Create")] internal static class SlapOncePerSwingPatch { private const float SameSwingSeconds = 0.25f; private static float _lastSlapTime = -100f; [HarmonyPrefix] private static void Prefix(EffectList __instance) { EffectData[] array = __instance?.m_effectPrefabs; if (array == null) { return; } GameObject whooshPrefab = RidingCropPlugin.WhooshPrefab; GameObject slapPrefab = RidingCropPlugin.SlapPrefab; if ((Object)(object)whooshPrefab == (Object)null && (Object)(object)slapPrefab == (Object)null) { return; } foreach (EffectData val in array) { if (val == null || (Object)(object)val.m_prefab == (Object)null) { continue; } if ((Object)(object)val.m_prefab == (Object)(object)whooshPrefab) { if (RidingCropPlugin.DebugLogging) { RidingCropPlugin.Log($"[sound] frame {Time.frameCount}: whoosh requested by an effect list (enabled={val.m_enabled})."); } } else if (!((Object)(object)val.m_prefab != (Object)(object)slapPrefab)) { float time = Time.time; bool flag = time >= _lastSlapTime && time - _lastSlapTime < 0.25f; val.m_enabled = !flag; if (!flag) { _lastSlapTime = time; } if (RidingCropPlugin.DebugLogging) { RidingCropPlugin.Log(flag ? $"[sound] frame {Time.frameCount}: duplicate slap in the same swing suppressed." : $"[sound] frame {Time.frameCount}: slap requested by an effect list."); } } } } } public class RidingCropSoundProbe : MonoBehaviour { public string Label = "sound"; private void OnEnable() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (RidingCropPlugin.DebugLogging) { RidingCropPlugin.Log($"[sound] frame {Time.frameCount}: '{Label}' spawned at {((Component)this).transform.position}."); ((MonoBehaviour)this).StartCoroutine(ReportNextFrame()); } } private IEnumerator ReportNextFrame() { int frame = Time.frameCount; yield return null; AudioSource componentInChildren = ((Component)this).GetComponentInChildren<AudioSource>(); if ((Object)(object)componentInChildren == (Object)null) { RidingCropPlugin.Log($"[sound] frame {frame}: '{Label}' has no AudioSource."); yield break; } RidingCropPlugin.Log($"[sound] frame {frame}: '{Label}' one frame later playing={componentInChildren.isPlaying}, volume={componentInChildren.volume:0.##}, " + string.Format("clip={0}, mute={1}, priority={2}, ", ((Object)(object)componentInChildren.clip != (Object)null) ? ((Object)componentInChildren.clip).name : "none", componentInChildren.mute, componentInChildren.priority) + $"spatialBlend={componentInChildren.spatialBlend:0.##}, listener volume={AudioListener.volume:0.##}."); } } public class SE_RidingCropBleed : StatusEffect { public float m_damagePerTick = 10f; public float m_tickInterval = 1f; public int m_ticksTotal = 5; private float _tickTimer; private int _ticksDone; private Character _attacker; private bool IsBleeding => _ticksDone < m_ticksTotal; public override void SetAttacker(Character attacker) { ((StatusEffect)this).SetAttacker(attacker); _attacker = attacker; } public void Configure(float damagePerSecond, float durationSeconds) { m_tickInterval = 1f; m_damagePerTick = damagePerSecond * m_tickInterval; m_ticksTotal = Mathf.Max(1, Mathf.RoundToInt(durationSeconds / m_tickInterval)); base.m_ttl = (float)m_ticksTotal * m_tickInterval + 0.5f * m_tickInterval; } public override void Setup(Character character) { ((StatusEffect)this).Setup(character); _tickTimer = m_tickInterval; _ticksDone = 0; RidingCropPlugin.Dbg(string.Format("[bleed] '{0}' started on '{1}': {2:0.#} x {3}.", ((Object)this).name, ((Object)(object)character != (Object)null) ? ((Object)character).name : "null", m_damagePerTick, m_ticksTotal)); } public override void ResetTime() { if (IsBleeding) { RidingCropPlugin.Dbg("[bleed] '" + ((Object)this).name + "' hit again while bleeding: ignored."); return; } ((StatusEffect)this).ResetTime(); _ticksDone = 0; _tickTimer = m_tickInterval; } public override bool CanAdd(Character character) { if ((Object)(object)character == (Object)null) { return ((StatusEffect)this).CanAdd(character); } SEMan sEMan = character.GetSEMan(); List<StatusEffect> list = ((sEMan != null) ? sEMan.GetStatusEffects() : null); if (list != null) { foreach (StatusEffect item in list) { SE_RidingCropBleed sE_RidingCropBleed = item as SE_RidingCropBleed; if ((Object)(object)sE_RidingCropBleed != (Object)null && sE_RidingCropBleed.IsBleeding) { RidingCropPlugin.Dbg("[bleed] '" + ((Object)this).name + "' not applied to '" + ((Object)character).name + "': '" + ((Object)sE_RidingCropBleed).name + "' is still bleeding."); return false; } } } return ((StatusEffect)this).CanAdd(character); } public override void UpdateStatusEffect(float dt) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) ((StatusEffect)this).UpdateStatusEffect(dt); if ((Object)(object)base.m_character == (Object)null || _ticksDone >= m_ticksTotal) { return; } _tickTimer -= dt; if (!(_tickTimer > 0f)) { _tickTimer += m_tickInterval; _ticksDone++; if (RidingCropPlugin.DebugLogging) { RidingCropPlugin.Dbg($"[bleed] '{((Object)this).name}' tick {_ticksDone}/{m_ticksTotal} on '{((Object)base.m_character).name}' for {m_damagePerTick:0.#}."); } HitData val = new HitData(); val.m_point = base.m_character.GetCenterPoint(); val.m_damage.m_damage = m_damagePerTick; val.m_hitType = (HitType)0; if ((Object)(object)_attacker != (Object)null) { val.SetAttacker(_attacker); } base.m_character.ApplyDamage(val, true, false, (DamageModifier)0); } } } }