Decompiled source of YoureInjured v1.4.1

YoureInjured.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace YoureInjured;

[BepInPlugin("com.marccunningham.youreinjured", "You're Injured", "1.5.0")]
[BepInProcess("valheim.exe")]
public sealed class YoureInjuredPlugin : BaseUnityPlugin
{
	private enum HudResizeHandle
	{
		None,
		TopLeft,
		TopRight,
		BottomLeft,
		BottomRight
	}

	private enum HitSoundKind
	{
		None,
		Axe,
		Sword,
		Arrow
	}

	public const string PluginGuid = "com.marccunningham.youreinjured";

	public const string PluginName = "You're Injured";

	public const string PluginVersion = "1.5.0";

	private const float MinimumValue = 0f;

	private const float MaximumValue = 100f;

	private const float TickIntervalSeconds = 1f;

	private const float SaveIntervalSeconds = 5f;

	private const float MinimumHealthLeft = 1f;

	private const float InjuryPanelHeight = 150f;

	private const float InjuryPanelMinimumBottomMargin = 12f;

	private const int LiquidBloodTextureSize = 192;

	private const int LiquidBloodTextureVariantCount = 7;

	private const float CompactHudReferenceWidth = 2048f;

	private const float CompactHudReferenceHeight = 1152f;

	private const float CompactInjuryReferenceLeft = 248f;

	private const float CompactInjuryReferenceBottom = 30f;

	private const float CompactInjuryReferenceWidth = 220f;

	private const float CompactInjuryReferenceHeight = 80f;

	private const string ZdoHead = "YoureInjured_Head";

	private const string ZdoTorso = "YoureInjured_Torso";

	private const string ZdoLeftArm = "YoureInjured_LeftArm";

	private const string ZdoRightArm = "YoureInjured_RightArm";

	private const string ZdoLeftLeg = "YoureInjured_LeftLeg";

	private const string ZdoRightLeg = "YoureInjured_RightLeg";

	private const string ZdoBleeding = "YoureInjured_Bleeding";

	private const string ZdoInfection = "YoureInjured_Infection";

	private const string ZdoInfectionRisk = "YoureInjured_InfectionRisk";

	internal static YoureInjuredPlugin Instance;

	private ConfigEntry<bool> modEnabled;

	private ConfigEntry<KeyCode> treatmentKey;

	private ConfigEntry<KeyCode> diagnosticKey;

	private ConfigEntry<KeyCode> sessionToggleKey;

	private ConfigEntry<string> difficultyPreset;

	private ConfigEntry<string> lastAppliedDifficultyPreset;

	private ConfigEntry<float> minimumStaminaRegenMultiplier;

	private ConfigEntry<bool> showHud;

	private ConfigEntry<bool> hideHudWithCtrlF3;

	private ConfigEntry<bool> useCompactSurvivalHud;

	private ConfigEntry<KeyCode> hudLayoutEditorKey;

	private ConfigEntry<float> compactHudXNormalized;

	private ConfigEntry<float> compactHudYNormalized;

	private ConfigEntry<float> compactHudWidthNormalized;

	private ConfigEntry<float> compactHudHeightNormalized;

	private ConfigEntry<bool> useSafeHudLayout;

	private ConfigEntry<float> hudPanelLeft;

	private ConfigEntry<float> hudPanelBottomOffset;

	private ConfigEntry<bool> stackBelowTemperatureHud;

	private ConfigEntry<bool> autoLiftTemperatureHudForInjuryPanel;

	private ConfigEntry<float> temperatureHudGapPixels;

	private ConfigEntry<float> temperatureHudFallbackLeft;

	private ConfigEntry<float> temperatureHudFallbackBottomOffset;

	private ConfigEntry<bool> verboseLogging;

	private ConfigEntry<float> minimumDamageForInjury;

	private ConfigEntry<float> injuryPerHealthLost;

	private ConfigEntry<float> fallInjuryMultiplier;

	private ConfigEntry<float> physicalBleedingThreshold;

	private ConfigEntry<float> bleedingPerHealthLost;

	private ConfigEntry<float> brokenBoneThreshold;

	private ConfigEntry<float> bleedingDamageAt100PerSecond;

	private ConfigEntry<float> naturalClottingPerSecond;

	private ConfigEntry<float> infectionRiskPerSecond;

	private ConfigEntry<float> wetInfectionRiskMultiplier;

	private ConfigEntry<float> infectionOnsetSeverity;

	private ConfigEntry<float> infectionGrowthPerSecond;

	private ConfigEntry<float> infectionRecoveryInBedPerSecond;

	private ConfigEntry<float> infectionDamageAt100PerSecond;

	private ConfigEntry<bool> enableSwimmingRinse;

	private ConfigEntry<float> swimmingRinseRequiredSeconds;

	private ConfigEntry<float> shelterRecoveryPerSecond;

	private ConfigEntry<float> bedRecoveryMultiplier;

	private ConfigEntry<float> recoveryStillSpeedLimit;

	private ConfigEntry<float> brokenLegRunPenalty;

	private ConfigEntry<float> legInjuryRunPenalty;

	private ConfigEntry<float> armInjuryAttackStaminaPenalty;

	private ConfigEntry<float> brokenArmAttackStaminaPenalty;

	private ConfigEntry<float> legInjuryRunStaminaPenalty;

	private ConfigEntry<float> headTorsoStaminaRegenPenalty;

	private ConfigEntry<float> infectionStaminaRegenPenalty;

	private ConfigEntry<float> legInjuryJumpStaminaPenalty;

	private ConfigEntry<string> bandageItemSharedName;

	private ConfigEntry<int> bandageItemCost;

	private ConfigEntry<float> bandageBleedingReduction;

	private ConfigEntry<float> bandageInfectionRiskReduction;

	private ConfigEntry<float> bandageInfectionReduction;

	private ConfigEntry<float> bandageWoundRelief;

	private ConfigEntry<float> treatmentCooldownSeconds;

	private ConfigEntry<bool> enableBleedingVisuals;

	private ConfigEntry<bool> spawnBloodFromSharpHits;

	private ConfigEntry<bool> enableBleedingTrail;

	private ConfigEntry<float> visibleBloodMinimumHealthLoss;

	private ConfigEntry<float> trailMinimumBleeding;

	private ConfigEntry<float> walkingTrailIntervalSeconds;

	private ConfigEntry<float> runningTrailIntervalSeconds;

	private ConfigEntry<float> groundBloodLifetimeSeconds;

	private ConfigEntry<int> maximumGroundBloodSplats;

	private ConfigEntry<int> maximumHitBloodDroplets;

	private ConfigEntry<float> bloodDropletGravity;

	private ConfigEntry<float> bloodSplatMinimumSize;

	private ConfigEntry<float> bloodSplatMaximumSize;

	private ConfigEntry<float> bloodLiquidSpreadSeconds;

	private ConfigEntry<bool> enableHitImpactSprites;

	private ConfigEntry<bool> cameraSafeHitSprites;

	private ConfigEntry<float> hitImpactSpriteLifetime;

	private ConfigEntry<float> hitImpactSpriteMaximumSize;

	private ConfigEntry<int> maximumImpactSpriteTextures;

	private ConfigEntry<bool> enableHitAudio;

	private ConfigEntry<float> hitAudioVolume;

	private ConfigEntry<float> hitAudioCooldownSeconds;

	private ConfigEntry<string> axeHitAudioFile;

	private ConfigEntry<string> swordHitAudioFile;

	private ConfigEntry<string> arrowHitAudioFile;

	private ConfigEntry<bool> enableBandageAudio;

	private ConfigEntry<float> bandageAudioVolume;

	private ConfigEntry<string> bandageAudioFile;

	private Harmony harmony;

	private readonly InjuryState state = new InjuryState();

	private GUIStyle injuryHeaderStyle;

	private GUIStyle injuryDetailStyle;

	private GUIStyle compactInjuryHeaderStyle;

	private GUIStyle compactInjuryDetailStyle;

	private bool hudLayoutEditorActive;

	private bool hudLayoutDragging;

	private HudResizeHandle hudResizeHandle;

	private Vector2 hudEditStartMouse;

	private Rect hudEditStartRect;

	private CursorLockMode hudPreviousCursorLockMode;

	private bool hudPreviousCursorVisible;

	private bool hudCursorStateCaptured;

	private bool hudHiddenByCtrlF3;

	private bool runtimeEnabled = true;

	private bool stateLoaded;

	private float tickTimer;

	private float saveTimer;

	private float treatmentCooldown;

	private int localDamageHookCalls;

	private int injuryEventsRecorded;

	private float lastDetectedHealthLoss;

	private HitType lastDetectedHitType;

	private readonly List<GroundBloodSplat> activeGroundBlood = new List<GroundBloodSplat>();

	private Transform bloodVisualRoot;

	private Material bloodDropMaterial;

	private Material[] bloodLiquidMaterials;

	private Texture2D[] bloodLiquidTextures;

	private float bleedingTrailTimer;

	private float swimmingRinseTimer;

	private int hitBloodAttempts;

	private int trailBloodAttempts;

	private int hitBloodDropletsSpawned;

	private int trailBloodDropletsSpawned;

	private int groundBloodSplatsSpawned;

	private int directTrailSplatsSpawned;

	private int groundProbeSuccesses;

	private int groundProbeFailures;

	private int dropletFallbackLandings;

	private string pluginDirectory;

	private readonly List<Texture2D> impactSpriteTextures = new List<Texture2D>();

	private readonly List<Material> impactSpriteMaterials = new List<Material>();

	private readonly List<Texture2D> dripSpriteTextures = new List<Texture2D>();

	private readonly List<Material> dripSpriteMaterials = new List<Material>();

	private Component hitAudioSource;

	private object axeHitAudioClip;

	private object swordHitAudioClip;

	private object arrowHitAudioClip;

	private object bandageAudioClip;

	private float bleedDripTimer;

	private float nextAllowedRecognizedHitAudioTime;

	private void Awake()
	{
		//IL_0e99: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ea3: Expected O, but got Unknown
		Instance = this;
		pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Set false to disable the entire injury system, including wounds, penalties, treatment and injury HUD.");
		treatmentKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "UseBandageKey", (KeyCode)103, "Press this key to use a bandage material and treat wounds. Change it if G conflicts with another mod.");
		diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "DiagnosticKey", (KeyCode)283, "Writes the current injury state to BepInEx/LogOutput.log.");
		sessionToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "SessionToggleKey", (KeyCode)284, "Emergency session toggle. This pauses or resumes injury effects without removing the DLL.");
		difficultyPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Difficulty", "Preset", "Normal", "Choose Easy, Normal, Hard, or Extreme. Change this setting, then restart Valheim to apply that mod's matching survival balance.");
		lastAppliedDifficultyPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Difficulty", "LastAppliedPreset", "Normal", "Internal preset tracking. Leave this alone; it records the last difficulty preset applied.");
		minimumStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Difficulty", "MinimumStaminaRegenMultiplier", 0.82f, "Safety floor for this mod's own injury and infection stamina-regeneration penalty. It prevents wounds from combining with other Scavengers penalties into a no-escape state.");
		showHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowInjuryPanel", true, "Set false to hide only the Injuries HUD while injury calculations and treatment continue running.");
		hideHudWithCtrlF3 = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "HideHudWithCtrlF3", true, "When enabled, Ctrl+F3 hides or restores this mod's HUD along with Valheim's HUD toggle. The injury system keeps running.");
		useCompactSurvivalHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "UseCompactSurvivalHud", true, "Places the injury panel beneath the Body Temp panel, under Nourishment and directly left of the Tired meter.");
		hudLayoutEditorKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("HUD Layout Editor", "ToggleInjuriesLayoutEditorKey", (KeyCode)111, "Press O to enter or leave Injuries HUD layout mode. In layout mode, drag the panel and drag a gold corner handle to resize it.");
		compactHudXNormalized = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "CompactInjuriesXNormalized", 0.12109375f, "Saved left position of the compact Injuries panel as a fraction of screen width.");
		compactHudYNormalized = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "CompactInjuriesYNormalized", 0.9045139f, "Saved top position of the compact Injuries panel as a fraction of screen height.");
		compactHudWidthNormalized = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "CompactInjuriesWidthNormalized", 0.107421875f, "Saved width of the compact Injuries panel as a fraction of screen width.");
		compactHudHeightNormalized = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "CompactInjuriesHeightNormalized", 5f / 72f, "Saved height of the compact Injuries panel as a fraction of screen height.");
		useSafeHudLayout = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "UseSafeLayout", true, "Uses the fixed stacked layout beneath the temperature gauge. It automatically keeps enough room for the full injury panel.");
		hudPanelLeft = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "PanelLeftPixels", 392f, "Manual panel left edge in pixels when UseSafeLayout is false.");
		hudPanelBottomOffset = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "PanelBottomOffsetPixels", 18f, "Manual clearance from the bottom of the screen in pixels when UseSafeLayout is false.");
		stackBelowTemperatureHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "StackDirectlyBelowTemperatureBar", true, "Keeps the injury panel directly below You're Cold's temperature bar, with an even gap. This is enabled by default so the two survival panels remain aligned.");
		autoLiftTemperatureHudForInjuryPanel = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "AutoLiftTemperatureHudForInjuryPanel", true, "Moves the temperature panel upward only when needed so the larger injury panel can remain directly beneath it without clipping off the bottom of the screen.");
		temperatureHudGapPixels = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "TemperatureHudGapPixels", 12f, "Even vertical gap between the bottom of the temperature panel and the top of the larger injury panel.");
		temperatureHudFallbackLeft = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "TemperatureHudFallbackLeftPixels", 460f, "Fallback temperature-panel left edge used only when You're Cold is not currently loaded.");
		temperatureHudFallbackBottomOffset = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "TemperatureHudFallbackBottomOffsetPixels", 330f, "Fallback temperature-panel bottom offset used only when You're Cold is not currently loaded.");
		verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Writes injury update details to LogOutput.log every tick. Keep disabled unless testing.");
		minimumDamageForInjury = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "MinimumHealthLossForInjury", 1f, "Actual health loss required before a hit can create an injury. V1.0.3 defaults to 1 so ordinary enemy hits are visible during testing.");
		injuryPerHealthLost = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "InjuryPointsPerHealthLost", 1.4f, "Injury points applied for each point of health actually lost after armour and resistances.");
		fallInjuryMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "FallInjuryMultiplier", 1.25f, "Extra injury multiplier for fall damage. Fall injuries are applied to both legs.");
		physicalBleedingThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "PhysicalDamageForBleeding", 8f, "Actual health loss required before slash or pierce damage can cause bleeding.");
		bleedingPerHealthLost = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "BleedingPointsPerHealthLost", 1.5f, "Bleeding points applied per health lost beyond the bleeding threshold.");
		brokenBoneThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "BrokenBoneThreshold", 78f, "An arm or leg at or above this injury value is treated as broken.");
		bleedingDamageAt100PerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Bleeding", "DamageAt100BleedingPerSecond", 0.24f, "Health lost each second at 100 bleeding. Bleeding will not reduce health below 1 in V1.");
		naturalClottingPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Bleeding", "NaturalClottingPerSecond", 0.06f, "Bleeding naturally decreases this much per second. Bandages are much faster.");
		infectionRiskPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "RiskGainPerSecond", 0.1f, "Infection risk gained per second from untreated serious wounds.");
		wetInfectionRiskMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "WetRiskMultiplier", 2f, "Multiplier applied to infection risk while Wet.");
		infectionOnsetSeverity = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "OnsetSeverity", 25f, "Infection severity created when infection risk reaches 100.");
		infectionGrowthPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "GrowthPerSecond", 0.04f, "How quickly an untreated infection worsens outside a bed.");
		infectionRecoveryInBedPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "RecoveryInBedPerSecond", 0.14f, "How quickly infection improves while sheltered in bed with no active bleeding.");
		infectionDamageAt100PerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "DamageAt100InfectionPerSecond", 0.12f, "Health lost each second at 100 infection. Infection will not reduce health below 1 in V1.");
		enableSwimmingRinse = ((BaseUnityPlugin)this).Config.Bind<bool>("Infection", "EnableColdWaterRinse", true, "Allows one continuous minute of swimming to rinse infection risk from a closed, non-infected wound. It does not cure an established infection and cannot be used while actively bleeding.");
		swimmingRinseRequiredSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Infection", "ColdWaterRinseSeconds", 60f, "Continuous swimming time required to clear infection risk from a closed wound. Leaving the water resets the rinse timer.");
		shelterRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "ShelterRecoveryPerSecond", 0.045f, "Injury points recovered per second while sheltered and still, with no bleeding or infection.");
		bedRecoveryMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "BedRecoveryMultiplier", 4.5f, "Recovery multiplier while resting in bed.");
		recoveryStillSpeedLimit = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "StillSpeedLimit", 0.25f, "Maximum movement speed that counts as resting for sheltered recovery.");
		brokenLegRunPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "BrokenLegRunPenalty", 0.18f, "Speed penalty per broken leg. Two broken legs are capped so movement remains possible.");
		legInjuryRunPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "LegInjuryRunPenaltyAt100", 0.22f, "Maximum speed penalty from non-broken leg injuries.");
		armInjuryAttackStaminaPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "ArmInjuryAttackStaminaPenaltyAt100", 0.28f, "Maximum extra attack stamina cost from arm injuries.");
		brokenArmAttackStaminaPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "BrokenArmAttackStaminaPenalty", 0.15f, "Extra attack stamina cost per broken arm.");
		legInjuryRunStaminaPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "LegInjuryRunStaminaPenaltyAt100", 0.22f, "Maximum extra run stamina drain from leg injuries.");
		headTorsoStaminaRegenPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "HeadTorsoStaminaRegenPenaltyAt100", 0.22f, "Maximum stamina regeneration reduction from head and torso injuries.");
		infectionStaminaRegenPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "InfectionStaminaRegenPenaltyAt100", 0.18f, "Maximum stamina regeneration reduction from infection.");
		legInjuryJumpStaminaPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "LegInjuryJumpStaminaPenaltyAt100", 0.2f, "Maximum extra jump stamina cost from leg injuries.");
		bandageItemSharedName = ((BaseUnityPlugin)this).Config.Bind<string>("Bandages", "BandageItemSharedName", "$item_leatherscraps", "Valheim shared item name consumed as a bandage. Default is Leather Scraps, so treatment is available from the early game. This is a material-based bandage system in V1, not a new custom item prefab.");
		bandageItemCost = ((BaseUnityPlugin)this).Config.Bind<int>("Bandages", "BandageItemCost", 1, "How many bandage material items are consumed per treatment.");
		bandageBleedingReduction = ((BaseUnityPlugin)this).Config.Bind<float>("Bandages", "BleedingReduction", 60f, "Bleeding removed by one treatment.");
		bandageInfectionRiskReduction = ((BaseUnityPlugin)this).Config.Bind<float>("Bandages", "InfectionRiskReduction", 40f, "Infection risk removed by one treatment.");
		bandageInfectionReduction = ((BaseUnityPlugin)this).Config.Bind<float>("Bandages", "InfectionReduction", 5f, "Existing infection reduced by one treatment. Sleeping while sheltered is the main recovery method.");
		bandageWoundRelief = ((BaseUnityPlugin)this).Config.Bind<float>("Bandages", "WoundRelief", 7f, "Small injury reduction applied to each body part by one treatment. Bandages do not immediately fix broken bones.");
		treatmentCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Bandages", "TreatmentCooldownSeconds", 1f, "Prevents accidental repeated bandage use from one key press.");
		enableBleedingVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual Bleeding", "Enabled", true, "Creates local visual blood droplets and glossy two-minute ground splats for the player when wounded. It does not alter damage, terrain, saves or networking.");
		spawnBloodFromSharpHits = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual Bleeding", "SpawnBloodFromSharpHits", true, "Spawns a small blood burst from qualifying slash or pierce hits, even before a wound becomes severe enough to leave a trail.");
		enableBleedingTrail = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual Bleeding", "EnableBleedingTrail", true, "Leaves intermittent drops while walking or running with meaningful active bleeding.");
		visibleBloodMinimumHealthLoss = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "MinimumHealthLossForVisibleBlood", 2f, "Health loss required from slash or pierce damage before a visible hit blood burst is created.");
		trailMinimumBleeding = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "MinimumBleedingForTrail", 5f, "Bleeding severity required before movement leaves a visible trail.");
		walkingTrailIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "WalkingTrailIntervalSeconds", 0.82f, "Time between trail drops while walking. The default leaves a clearly readable but safe blood trail.");
		runningTrailIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "RunningTrailIntervalSeconds", 0.44f, "Time between trail drops while running.");
		groundBloodLifetimeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "GroundBloodLifetimeSeconds", 120f, "How long landed blood remains visible on the ground. Default is two minutes and the final fade only begins in the last twelve seconds.");
		maximumGroundBloodSplats = ((BaseUnityPlugin)this).Config.Bind<int>("Visual Bleeding", "MaximumGroundBloodSplats", 240, "Safety cap for active ground blood visuals. The oldest splat is removed when this limit is reached.");
		maximumHitBloodDroplets = ((BaseUnityPlugin)this).Config.Bind<int>("Visual Bleeding", "MaximumHitBloodDroplets", 14, "Maximum droplets produced by one strong slash, axe or arrow hit.");
		bloodDropletGravity = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "DropletGravity", 14f, "Downward acceleration for visual blood droplets. Slightly above real gravity keeps the fall readable in-game.");
		bloodSplatMinimumSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "GroundSplatMinimumSize", 0.17f, "Smallest ground blood splat diameter in metres.");
		bloodSplatMaximumSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "GroundSplatMaximumSize", 0.52f, "Largest ground blood splat diameter in metres.");
		bloodLiquidSpreadSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "BloodLiquidSpreadSeconds", 0.65f, "Seconds for a fresh blood splat to settle and spread across the ground. Short but visible, so blood feels liquid rather than stamped on.");
		enableHitImpactSprites = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual Bleeding", "EnableHitImpactSprites", false, "Optional world-space hit burst using supplied blood-spray frames. Disabled by default because the player-hit burst is not needed and can read like a red screen flash.");
		cameraSafeHitSprites = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual Bleeding", "CameraSafeHitSprites", true, "Skips a hit-sprite if the wound is too close to the gameplay camera, preventing a red full-screen blink.");
		hitImpactSpriteLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "HitImpactSpriteLifetimeSeconds", 0.14f, "How long the small sprite-based blood burst remains visible.");
		hitImpactSpriteMaximumSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visual Bleeding", "HitImpactSpriteMaximumSize", 0.38f, "Largest world-space size of a hit blood-spray sprite.");
		maximumImpactSpriteTextures = ((BaseUnityPlugin)this).Config.Bind<int>("Visual Bleeding", "MaximumImpactSpriteTextures", 4, "Maximum number of supplied blood-spray textures loaded from assets/bleeding/impact_frames.");
		enableHitAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Hit Audio", "Enabled", true, "Plays one local hit sound for qualifying player hits. Axe, sword, and arrow MP3 files are loaded externally beside the DLL.");
		hitAudioVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Hit Audio", "Volume", 0.65f, "Volume for externally loaded hit sounds.");
		hitAudioCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Hit Audio", "RecognizedHitSoundCooldownSeconds", 0.18f, "Minimum gap between correctly recognized axe, sword or arrow hit sounds. This prevents duplicate sounds from a single combat event.");
		axeHitAudioFile = ((BaseUnityPlugin)this).Config.Bind<string>("Hit Audio", "AxeHitFile", "axe_hit.mp3", "MP3 filename expected in assets/audio beside the You're Injured DLL.");
		swordHitAudioFile = ((BaseUnityPlugin)this).Config.Bind<string>("Hit Audio", "SwordHitFile", "sword_hit.mp3", "MP3 filename expected in assets/audio beside the You're Injured DLL.");
		arrowHitAudioFile = ((BaseUnityPlugin)this).Config.Bind<string>("Hit Audio", "ArrowHitFile", "arrow_hit.mp3", "MP3 filename expected in assets/audio beside the You're Injured DLL.");
		enableBandageAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Bandage Audio", "Enabled", true, "Plays the supplied cloth-wrap sound only after a bandage is successfully applied and its material is consumed.");
		bandageAudioVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Bandage Audio", "Volume", 0.68f, "Volume for the externally loaded bandage-wrap sound.");
		bandageAudioFile = ((BaseUnityPlugin)this).Config.Bind<string>("Bandage Audio", "BandageWrapFile", "bandage wrap.mp3", "MP3 filename expected in assets/audio beside the You're Injured DLL.");
		if (string.Equals(bandageItemSharedName.Value, "$item_linen", StringComparison.Ordinal))
		{
			bandageItemSharedName.Value = "$item_leatherscraps";
		}
		if (Mathf.Abs(minimumDamageForInjury.Value - 5f) < 0.01f)
		{
			minimumDamageForInjury.Value = 1f;
		}
		if (Mathf.Abs(hudPanelLeft.Value - 460f) < 0.01f || Mathf.Abs(hudPanelLeft.Value - 417f) < 0.01f || Mathf.Abs(hudPanelLeft.Value - 406f) < 0.01f)
		{
			hudPanelLeft.Value = 392f;
		}
		if (Mathf.Abs(hudPanelBottomOffset.Value - 165f) < 0.01f || Mathf.Abs(hudPanelBottomOffset.Value - 170f) < 0.01f || Mathf.Abs(hudPanelBottomOffset.Value - 140f) < 0.01f || Mathf.Abs(hudPanelBottomOffset.Value - 100f) < 0.01f)
		{
			hudPanelBottomOffset.Value = 18f;
		}
		if (Mathf.Abs(walkingTrailIntervalSeconds.Value - 1.35f) < 0.01f)
		{
			walkingTrailIntervalSeconds.Value = 0.82f;
		}
		if (Mathf.Abs(runningTrailIntervalSeconds.Value - 0.68f) < 0.01f)
		{
			runningTrailIntervalSeconds.Value = 0.44f;
		}
		if (maximumGroundBloodSplats.Value == 160)
		{
			maximumGroundBloodSplats.Value = 240;
		}
		if (maximumHitBloodDroplets.Value == 5)
		{
			maximumHitBloodDroplets.Value = 14;
		}
		if (Mathf.Abs(bloodSplatMinimumSize.Value - 0.11f) < 0.01f)
		{
			bloodSplatMinimumSize.Value = 0.17f;
		}
		if (Mathf.Abs(bloodSplatMaximumSize.Value - 0.28f) < 0.01f)
		{
			bloodSplatMaximumSize.Value = 0.52f;
		}
		((BaseUnityPlugin)this).Config.Save();
		MigrateLegacyDefaultsToNormal();
		ApplyDifficultyPresetIfChanged();
		LoadExternalImpactSprites();
		((MonoBehaviour)this).StartCoroutine(LoadHitAudioFiles());
		harmony = new Harmony("com.marccunningham.youreinjured");
		harmony.PatchAll(typeof(YoureInjuredPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Injured 1.5.0 loaded. G uses Leather Scraps as bandage material, F2 logs diagnostics, and F3 toggles injury effects for this session. V1.3.5 adds a heavier directional wound spray, larger persistent blood pools, and strict weapon-recognized hit audio.");
	}

	private void MigrateLegacyDefaultsToNormal()
	{
		if (Mathf.Abs(injuryPerHealthLost.Value - 1.6f) < 0.001f && Mathf.Abs(fallInjuryMultiplier.Value - 1.4f) < 0.001f && Mathf.Abs(bleedingPerHealthLost.Value - 1.8f) < 0.001f && Mathf.Abs(brokenBoneThreshold.Value - 75f) < 0.001f && Mathf.Abs(headTorsoStaminaRegenPenalty.Value - 0.35f) < 0.001f && Mathf.Abs(infectionStaminaRegenPenalty.Value - 0.3f) < 0.001f)
		{
			ApplyDifficultyPreset("Normal");
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Injured: migrated untouched legacy injury defaults to the balanced Normal preset.");
		}
	}

	private void ApplyDifficultyPresetIfChanged()
	{
		string text = NormalizeDifficultyPreset(difficultyPreset.Value);
		if (!string.Equals(difficultyPreset.Value, text, StringComparison.OrdinalIgnoreCase))
		{
			difficultyPreset.Value = text;
		}
		if (!string.Equals(lastAppliedDifficultyPreset.Value, text, StringComparison.OrdinalIgnoreCase))
		{
			ApplyDifficultyPreset(text);
			lastAppliedDifficultyPreset.Value = text;
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Injured: applied " + text + " difficulty preset."));
		}
	}

	private static string NormalizeDifficultyPreset(string value)
	{
		if (string.Equals(value, "Easy", StringComparison.OrdinalIgnoreCase))
		{
			return "Easy";
		}
		if (string.Equals(value, "Hard", StringComparison.OrdinalIgnoreCase))
		{
			return "Hard";
		}
		if (string.Equals(value, "Extreme", StringComparison.OrdinalIgnoreCase))
		{
			return "Extreme";
		}
		return "Normal";
	}

	private void ApplyDifficultyPreset(string preset)
	{
		switch (preset)
		{
		case "Easy":
			injuryPerHealthLost.Value = 1f;
			fallInjuryMultiplier.Value = 1.1f;
			bleedingPerHealthLost.Value = 1.1f;
			brokenBoneThreshold.Value = 85f;
			bleedingDamageAt100PerSecond.Value = 0.16f;
			naturalClottingPerSecond.Value = 0.08f;
			infectionRiskPerSecond.Value = 0.07f;
			wetInfectionRiskMultiplier.Value = 1.7f;
			infectionGrowthPerSecond.Value = 0.025f;
			infectionRecoveryInBedPerSecond.Value = 0.18f;
			infectionDamageAt100PerSecond.Value = 0.09f;
			shelterRecoveryPerSecond.Value = 0.06f;
			bedRecoveryMultiplier.Value = 5f;
			brokenLegRunPenalty.Value = 0.14f;
			legInjuryRunPenalty.Value = 0.16f;
			legInjuryRunStaminaPenalty.Value = 0.16f;
			headTorsoStaminaRegenPenalty.Value = 0.16f;
			infectionStaminaRegenPenalty.Value = 0.12f;
			minimumStaminaRegenMultiplier.Value = 0.9f;
			bandageBleedingReduction.Value = 68f;
			bandageInfectionRiskReduction.Value = 48f;
			bandageInfectionReduction.Value = 7f;
			bandageWoundRelief.Value = 9f;
			break;
		case "Hard":
			injuryPerHealthLost.Value = 1.85f;
			fallInjuryMultiplier.Value = 1.55f;
			bleedingPerHealthLost.Value = 2f;
			brokenBoneThreshold.Value = 70f;
			bleedingDamageAt100PerSecond.Value = 0.34f;
			naturalClottingPerSecond.Value = 0.035f;
			infectionRiskPerSecond.Value = 0.15f;
			wetInfectionRiskMultiplier.Value = 3f;
			infectionGrowthPerSecond.Value = 0.07f;
			infectionRecoveryInBedPerSecond.Value = 0.09f;
			infectionDamageAt100PerSecond.Value = 0.22f;
			shelterRecoveryPerSecond.Value = 0.025f;
			bedRecoveryMultiplier.Value = 3f;
			brokenLegRunPenalty.Value = 0.25f;
			legInjuryRunPenalty.Value = 0.34f;
			legInjuryRunStaminaPenalty.Value = 0.34f;
			headTorsoStaminaRegenPenalty.Value = 0.32f;
			infectionStaminaRegenPenalty.Value = 0.28f;
			minimumStaminaRegenMultiplier.Value = 0.75f;
			bandageBleedingReduction.Value = 48f;
			bandageInfectionRiskReduction.Value = 30f;
			bandageInfectionReduction.Value = 3f;
			bandageWoundRelief.Value = 4f;
			break;
		case "Extreme":
			injuryPerHealthLost.Value = 2.3f;
			fallInjuryMultiplier.Value = 1.8f;
			bleedingPerHealthLost.Value = 2.4f;
			brokenBoneThreshold.Value = 65f;
			bleedingDamageAt100PerSecond.Value = 0.42f;
			naturalClottingPerSecond.Value = 0.025f;
			infectionRiskPerSecond.Value = 0.2f;
			wetInfectionRiskMultiplier.Value = 3.6f;
			infectionGrowthPerSecond.Value = 0.095f;
			infectionRecoveryInBedPerSecond.Value = 0.065f;
			infectionDamageAt100PerSecond.Value = 0.3f;
			shelterRecoveryPerSecond.Value = 0.018f;
			bedRecoveryMultiplier.Value = 2.4f;
			brokenLegRunPenalty.Value = 0.3f;
			legInjuryRunPenalty.Value = 0.4f;
			legInjuryRunStaminaPenalty.Value = 0.4f;
			headTorsoStaminaRegenPenalty.Value = 0.38f;
			infectionStaminaRegenPenalty.Value = 0.34f;
			minimumStaminaRegenMultiplier.Value = 0.68f;
			bandageBleedingReduction.Value = 38f;
			bandageInfectionRiskReduction.Value = 22f;
			bandageInfectionReduction.Value = 2f;
			bandageWoundRelief.Value = 3f;
			break;
		default:
			injuryPerHealthLost.Value = 1.4f;
			fallInjuryMultiplier.Value = 1.25f;
			bleedingPerHealthLost.Value = 1.5f;
			brokenBoneThreshold.Value = 78f;
			bleedingDamageAt100PerSecond.Value = 0.24f;
			naturalClottingPerSecond.Value = 0.06f;
			infectionRiskPerSecond.Value = 0.1f;
			wetInfectionRiskMultiplier.Value = 2f;
			infectionGrowthPerSecond.Value = 0.04f;
			infectionRecoveryInBedPerSecond.Value = 0.14f;
			infectionDamageAt100PerSecond.Value = 0.12f;
			shelterRecoveryPerSecond.Value = 0.045f;
			bedRecoveryMultiplier.Value = 4.5f;
			brokenLegRunPenalty.Value = 0.18f;
			legInjuryRunPenalty.Value = 0.22f;
			legInjuryRunStaminaPenalty.Value = 0.22f;
			headTorsoStaminaRegenPenalty.Value = 0.22f;
			infectionStaminaRegenPenalty.Value = 0.18f;
			minimumStaminaRegenMultiplier.Value = 0.82f;
			bandageBleedingReduction.Value = 60f;
			bandageInfectionRiskReduction.Value = 40f;
			bandageInfectionReduction.Value = 5f;
			bandageWoundRelief.Value = 7f;
			break;
		}
	}

	private void OnDestroy()
	{
		RestoreHudCursor();
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		DestroyBloodVisuals();
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void Update()
	{
		//IL_0032: 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)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		if (TryToggleHudWithCtrlF3())
		{
			return;
		}
		if (hudLayoutEditorActive && (!showHud.Value || IsHudHiddenByCtrlF3()))
		{
			CloseHudLayoutEditorForHiddenHud();
		}
		if (Input.GetKeyDown(hudLayoutEditorKey.Value) && showHud.Value && !IsHudHiddenByCtrlF3())
		{
			ToggleHudLayoutEditor();
		}
		if (Input.GetKeyDown(diagnosticKey.Value))
		{
			WriteDiagnostic();
		}
		if (Input.GetKeyDown(sessionToggleKey.Value))
		{
			runtimeEnabled = !runtimeEnabled;
			ShowMessage("You're Injured: " + (runtimeEnabled ? "ON" : "OFF"));
		}
		if (!runtimeEnabled || !modEnabled.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			EnsureStateLoaded(localPlayer);
			if (Input.GetKeyDown(treatmentKey.Value))
			{
				TryUseBandage(localPlayer);
			}
			float deltaTime = Time.deltaTime;
			treatmentCooldown = Mathf.Max(0f, treatmentCooldown - deltaTime);
			UpdateBleedingTrail(localPlayer, deltaTime);
			UpdateBleedingDrips(localPlayer, deltaTime);
			tickTimer += deltaTime;
			saveTimer += deltaTime;
			if (tickTimer >= 1f)
			{
				float elapsedSeconds = Mathf.Min(tickTimer, 3f);
				tickTimer = 0f;
				TickInjuries(localPlayer, elapsedSeconds);
			}
			if (saveTimer >= 5f)
			{
				saveTimer = 0f;
				SaveState(localPlayer);
			}
		}
	}

	internal bool IsActiveFor(Player player)
	{
		if (runtimeEnabled && modEnabled.Value && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer)
		{
			return stateLoaded;
		}
		return false;
	}

	internal float GetRunSpeedMultiplier()
	{
		float threshold = Mathf.Clamp(brokenBoneThreshold.Value, 1f, 100f);
		float num = state.GetAverageLegInjury() / 100f;
		float num2 = 1f - num * Mathf.Clamp01(legInjuryRunPenalty.Value);
		if (state.IsBroken(Limb.LeftLeg, threshold))
		{
			num2 -= Mathf.Clamp01(brokenLegRunPenalty.Value);
		}
		if (state.IsBroken(Limb.RightLeg, threshold))
		{
			num2 -= Mathf.Clamp01(brokenLegRunPenalty.Value);
		}
		return Mathf.Clamp(num2, 0.3f, 1f);
	}

	internal float GetAttackStaminaMultiplier()
	{
		float threshold = Mathf.Clamp(brokenBoneThreshold.Value, 1f, 100f);
		float num = state.GetAverageArmInjury() / 100f;
		float num2 = 1f + num * Mathf.Max(0f, armInjuryAttackStaminaPenalty.Value);
		if (state.IsBroken(Limb.LeftArm, threshold))
		{
			num2 += Mathf.Max(0f, brokenArmAttackStaminaPenalty.Value);
		}
		if (state.IsBroken(Limb.RightArm, threshold))
		{
			num2 += Mathf.Max(0f, brokenArmAttackStaminaPenalty.Value);
		}
		return Mathf.Max(1f, num2);
	}

	internal float GetRunStaminaMultiplier()
	{
		float num = state.GetAverageLegInjury() / 100f;
		return Mathf.Max(1f, 1f + num * Mathf.Max(0f, legInjuryRunStaminaPenalty.Value));
	}

	internal float GetJumpStaminaMultiplier()
	{
		float num = state.GetAverageLegInjury() / 100f;
		return Mathf.Max(1f, 1f + num * Mathf.Max(0f, legInjuryJumpStaminaPenalty.Value));
	}

	internal float GetStaminaRegenMultiplier()
	{
		float num = (state.Head + state.Torso) / 200f * Mathf.Clamp01(headTorsoStaminaRegenPenalty.Value);
		float num2 = state.Infection / 100f * Mathf.Clamp01(infectionStaminaRegenPenalty.Value);
		float num3 = Mathf.Clamp(minimumStaminaRegenMultiplier.Value, 0.1f, 1f);
		return Mathf.Clamp(1f - num - num2, num3, 1f);
	}

	internal void RecordAppliedDamage(Player player, HitData hit, float healthBefore)
	{
		//IL_0037: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Invalid comparison between Unknown and I4
		if (!IsActiveFor(player) || hit == null)
		{
			return;
		}
		float num = Mathf.Max(0f, healthBefore - ((Character)player).GetHealth());
		localDamageHookCalls++;
		lastDetectedHealthLoss = num;
		lastDetectedHitType = hit.m_hitType;
		if (verboseLogging.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Damage hook: health loss=" + num.ToString("0.0") + ", type=" + ((object)Unsafe.As<HitType, HitType>(ref hit.m_hitType)/*cast due to .constrained prefix*/).ToString() + ", threshold=" + minimumDamageForInjury.Value.ToString("0.0")));
		}
		if (!(num < Mathf.Max(0f, minimumDamageForInjury.Value)) && !ShouldIgnoreInjuryHit(hit.m_hitType))
		{
			float num2 = num * Mathf.Max(0f, injuryPerHealthLost.Value);
			if ((int)hit.m_hitType == 3)
			{
				num2 *= Mathf.Max(0f, fallInjuryMultiplier.Value);
				state.Add(Limb.LeftLeg, num2 * 0.5f);
				state.Add(Limb.RightLeg, num2 * 0.5f);
			}
			else
			{
				state.Add(ResolveHitLimb(player, hit), num2);
			}
			float bleedingAdded = ApplyBleedingFromHit(hit, num);
			state.ClampAll();
			TrySpawnHitBlood(player, hit, num, bleedingAdded);
			TryPlayHitAudio(hit);
			injuryEventsRecorded++;
			SaveState(player);
			ShowMessage(BuildDamageMessage(num));
			if (verboseLogging.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied damage " + num.ToString("0.0") + ", hitType=" + ((object)Unsafe.As<HitType, HitType>(ref hit.m_hitType)/*cast due to .constrained prefix*/).ToString() + ", injuries=" + state.ToDiagnosticText()));
			}
		}
	}

	private void TickInjuries(Player player, float elapsedSeconds)
	{
		if (((Character)player).IsDead())
		{
			state.Bleeding = 0f;
			return;
		}
		ProcessBleeding(player, elapsedSeconds);
		ProcessInfection(player, elapsedSeconds);
		ProcessRecovery(player, elapsedSeconds);
		state.ClampAll();
		if (verboseLogging.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Tick: " + state.ToDiagnosticText()));
		}
	}

	private void ProcessBleeding(Player player, float elapsedSeconds)
	{
		if (!(state.Bleeding <= 0f))
		{
			float healthLoss = state.Bleeding / 100f * Mathf.Max(0f, bleedingDamageAt100PerSecond.Value) * elapsedSeconds;
			ApplyNonLethalHealthLoss(player, healthLoss);
			float num = Mathf.Max(0f, naturalClottingPerSecond.Value) * elapsedSeconds;
			if (player.InShelter() && !IsWet(player))
			{
				num *= 2f;
			}
			state.Bleeding = Mathf.Max(0f, state.Bleeding - num);
		}
	}

	private void ProcessInfection(Player player, float elapsedSeconds)
	{
		bool flag = IsWet(player);
		bool flag2 = state.Bleeding >= 5f || state.GetAverageLimbInjury() >= 35f || state.Torso >= 35f;
		bool flag3 = UpdateColdWaterRinse(player, elapsedSeconds);
		if (flag2 && state.Infection <= 0f && !flag3)
		{
			float num = Mathf.Max(0f, infectionRiskPerSecond.Value) * elapsedSeconds;
			if (flag)
			{
				num *= Mathf.Max(1f, wetInfectionRiskMultiplier.Value);
			}
			if (player.InShelter())
			{
				num *= 0.5f;
			}
			state.InfectionRisk += num;
			if (state.InfectionRisk >= 100f)
			{
				state.InfectionRisk = 0f;
				state.Infection = Mathf.Max(state.Infection, Mathf.Clamp(infectionOnsetSeverity.Value, 1f, 100f));
				ShowMessage("An untreated wound has become infected.");
			}
		}
		else if (!flag2 && state.Infection <= 0f)
		{
			state.InfectionRisk = Mathf.Max(0f, state.InfectionRisk - elapsedSeconds * 0.25f);
		}
		if (!(state.Infection <= 0f))
		{
			if (((Character)player).InBed() && player.InShelter() && !flag && state.Bleeding <= 0.01f)
			{
				state.Infection = Mathf.Max(0f, state.Infection - Mathf.Max(0f, infectionRecoveryInBedPerSecond.Value) * elapsedSeconds);
				return;
			}
			state.Infection += Mathf.Max(0f, infectionGrowthPerSecond.Value) * elapsedSeconds;
			float healthLoss = state.Infection / 100f * Mathf.Max(0f, infectionDamageAt100PerSecond.Value) * elapsedSeconds;
			ApplyNonLethalHealthLoss(player, healthLoss);
		}
	}

	private bool UpdateColdWaterRinse(Player player, float elapsedSeconds)
	{
		if (!enableSwimmingRinse.Value || (Object)(object)player == (Object)null || state.Infection > 0.01f)
		{
			swimmingRinseTimer = 0f;
			return false;
		}
		if (!((Character)player).IsSwimming() || !(state.Bleeding <= 0.01f) || !(state.InfectionRisk > 0.01f))
		{
			swimmingRinseTimer = 0f;
			return false;
		}
		swimmingRinseTimer += elapsedSeconds;
		if (swimmingRinseTimer >= Mathf.Max(1f, swimmingRinseRequiredSeconds.Value))
		{
			state.InfectionRisk = 0f;
			swimmingRinseTimer = 0f;
			ShowMessage("Cold water has rinsed the infection risk. Dry off and bandage the wound.");
			return false;
		}
		return true;
	}

	private void ProcessRecovery(Player player, float elapsedSeconds)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		if (state.Bleeding > 0.01f || state.Infection > 0.01f || IsWet(player) || !player.InShelter())
		{
			return;
		}
		bool flag = ((Character)player).InBed();
		Vector3 velocity = ((Character)player).GetVelocity();
		bool flag2 = ((Vector3)(ref velocity)).magnitude <= Mathf.Max(0.01f, recoveryStillSpeedLimit.Value);
		if (flag || flag2)
		{
			float num = Mathf.Max(0f, shelterRecoveryPerSecond.Value) * elapsedSeconds;
			if (flag)
			{
				num *= Mathf.Max(1f, bedRecoveryMultiplier.Value);
			}
			state.ReduceAllInjuries(num);
		}
	}

	private float ApplyBleedingFromHit(HitData hit, float actualHealthLoss)
	{
		if (Mathf.Max(0f, hit.m_damage.m_slash) + Mathf.Max(0f, hit.m_damage.m_pierce) + Mathf.Max(0f, hit.m_damage.m_chop) <= 0f || actualHealthLoss < Mathf.Max(0f, physicalBleedingThreshold.Value))
		{
			return 0f;
		}
		float num = (actualHealthLoss - Mathf.Max(0f, physicalBleedingThreshold.Value)) * Mathf.Max(0f, bleedingPerHealthLost.Value);
		state.Bleeding += num;
		return num;
	}

	private void UpdateBleedingTrail(Player player, float deltaSeconds)
	{
		//IL_0066: 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)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: 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_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//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_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		if (!enableBleedingVisuals.Value || !enableBleedingTrail.Value || (Object)(object)player == (Object)null || ((Character)player).IsSwimming())
		{
			bleedingTrailTimer = 0f;
			return;
		}
		if (state.Bleeding < Mathf.Max(0f, trailMinimumBleeding.Value))
		{
			bleedingTrailTimer = 0f;
			return;
		}
		Vector3 velocity = ((Character)player).GetVelocity();
		velocity.y = 0f;
		if (((Vector3)(ref velocity)).sqrMagnitude <= 0.1f)
		{
			return;
		}
		float num = (((Character)player).IsRunning() ? Mathf.Max(0.1f, runningTrailIntervalSeconds.Value) : Mathf.Max(0.1f, walkingTrailIntervalSeconds.Value));
		bleedingTrailTimer += deltaSeconds;
		if (!(bleedingTrailTimer < num))
		{
			bleedingTrailTimer = 0f;
			trailBloodAttempts++;
			Vector3 val = ((Character)player).GetCenterPoint() - Vector3.up * 0.18f;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(Random.Range(-0.12f, 0.12f), 0f, Random.Range(-0.12f, 0.12f));
			bool flag = TryPlaceBloodOnGround(player, val + val2, trailDrop: true);
			if (flag)
			{
				directTrailSplatsSpawned++;
			}
			SpawnBloodDroplet(((Component)player).transform, val + val2, val2 * 1.25f + Vector3.up * 0.35f, 0.04f, 0.72f, trailDrop: false, !flag);
			trailBloodDropletsSpawned++;
		}
	}

	private void UpdateBleedingDrips(Player player, float deltaSeconds)
	{
		//IL_00b6: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//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_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: 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_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		if (!enableBleedingVisuals.Value || (Object)(object)player == (Object)null || ((Character)player).IsSwimming() || state.Bleeding <= 0.01f)
		{
			bleedDripTimer = 0f;
			return;
		}
		float num = Mathf.InverseLerp(0f, 100f, state.Bleeding);
		float num2 = Mathf.Lerp(0.72f, 0.4f, num);
		bleedDripTimer += deltaSeconds;
		if (bleedDripTimer < num2)
		{
			return;
		}
		bleedDripTimer = 0f;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(Random.Range(-0.13f, 0.13f), 0f, Random.Range(-0.13f, 0.13f));
		Vector3 val2 = ((Character)player).GetCenterPoint() - Vector3.up * Random.Range(0.16f, 0.42f) + val;
		Vector3 velocity = ((Character)player).GetVelocity();
		velocity.y = 0f;
		bool flag = TryPlaceBloodOnGround(player, val2, trailDrop: true);
		if (flag)
		{
			directTrailSplatsSpawned++;
		}
		if (num >= 0.45f)
		{
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(Random.Range(-0.2f, 0.2f), 0f, Random.Range(-0.2f, 0.2f));
			if (TryPlaceBloodOnGround(player, val2 + val3, trailDrop: true))
			{
				directTrailSplatsSpawned++;
			}
		}
		SpawnBloodDroplet(((Component)player).transform, val2, velocity * 0.16f + val * 0.7f + Vector3.up * Random.Range(0.08f, 0.26f), Mathf.Lerp(0.045f, 0.07f, num), 1.5f, trailDrop: true, !flag);
		trailBloodDropletsSpawned++;
	}

	private void TrySpawnHitBlood(Player player, HitData hit, float actualHealthLoss, float bleedingAdded)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: 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_00a1: 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_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: 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_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_026c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		if (!enableBleedingVisuals.Value || !spawnBloodFromSharpHits.Value || (Object)(object)player == (Object)null || hit == null || Mathf.Max(0f, hit.m_damage.m_slash) + Mathf.Max(0f, hit.m_damage.m_pierce) + Mathf.Max(0f, hit.m_damage.m_chop) <= 0f || actualHealthLoss < Mathf.Max(0f, visibleBloodMinimumHealthLoss.Value))
		{
			return;
		}
		hitBloodAttempts++;
		Vector3 val = ResolvePlayerImpactPoint(player, hit);
		Vector3 val2 = ResolveOutwardBloodDirection(player, hit, val);
		float num = Mathf.Clamp01((actualHealthLoss - visibleBloodMinimumHealthLoss.Value) / 12f);
		bool flag = actualHealthLoss >= 6f || bleedingAdded > 0.01f;
		int num2 = Mathf.Clamp(maximumHitBloodDroplets.Value, 4, 22);
		int num3 = 5 + Mathf.RoundToInt(Mathf.Lerp(2f, (float)num2 - 5f, num));
		if (bleedingAdded > 0.01f)
		{
			num3 += 2;
		}
		if (flag)
		{
			num3 += 2;
		}
		num3 = Mathf.Clamp(num3, 5, num2);
		TryPlaceBloodOnGround(player, val + val2 * Random.Range(0.25f, 0.48f), trailDrop: false);
		if (flag)
		{
			Vector3 val3 = Vector3.Cross(Vector3.up, val2);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			TryPlaceBloodOnGround(player, val + val2 * Random.Range(0.42f, 0.72f) + normalized * Random.Range(-0.22f, 0.22f), trailDrop: false);
		}
		SpawnHitImpactSprite(val, val2, num);
		for (int i = 0; i < num3; i++)
		{
			float num4 = (flag ? 0.72f : 0.52f);
			Vector3 val4 = val2 + new Vector3(Random.Range(0f - num4, num4), Random.Range(-0.05f, 0.32f), Random.Range(0f - num4, num4));
			if (((Vector3)(ref val4)).sqrMagnitude < 0.01f)
			{
				val4 = ((Component)player).transform.forward;
			}
			((Vector3)(ref val4)).Normalize();
			float num5 = (flag ? Random.Range(2.7f, 5.1f) : Random.Range(2f, 4f));
			Vector3 initialVelocity = val4 * num5 + Vector3.up * Random.Range(1.7f, flag ? 3.85f : 3.1f);
			float size = (flag ? Random.Range(0.04f, 0.082f) : Random.Range(0.034f, 0.066f));
			SpawnBloodDroplet(((Component)player).transform, val, initialVelocity, size, 1.8f, trailDrop: false, createSplatWhenLanding: true);
			hitBloodDropletsSpawned++;
		}
	}

	private static Vector3 ResolvePlayerImpactPoint(Player player, HitData hit)
	{
		//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_0012: 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_0017: 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_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: 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_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_003e: 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_0049: 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)
		Vector3 centerPoint = ((Character)player).GetCenterPoint();
		Vector3 val = hit?.m_point ?? Vector3.zero;
		if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
		{
			Vector3 val2 = val - centerPoint;
			if (!(((Vector3)(ref val2)).sqrMagnitude > 9f))
			{
				goto IL_003e;
			}
		}
		val = centerPoint;
		goto IL_003e;
		IL_003e:
		return val + Vector3.up * 0.035f;
	}

	private static Vector3 ResolveOutwardBloodDirection(Player player, HitData hit, Vector3 impactPoint)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: 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_002a: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: 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_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = hit?.m_dir ?? Vector3.zero;
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
		{
			val = ((Component)player).transform.forward;
		}
		((Vector3)(ref val)).Normalize();
		Vector3 val2 = impactPoint - ((Character)player).GetCenterPoint();
		val2.y *= 0.55f;
		if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
		{
			val2 = val;
		}
		else
		{
			((Vector3)(ref val2)).Normalize();
			if (Vector3.Dot(val2, val) < 0f)
			{
				val2 = -val2;
			}
		}
		Vector3 val3 = val * 0.78f + val2 * 0.32f + Vector3.up * 0.08f;
		if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
		{
			val3 = ((Component)player).transform.forward;
		}
		val3.y = Mathf.Clamp(val3.y, -0.1f, 0.38f);
		return ((Vector3)(ref val3)).normalized;
	}

	private void SpawnHitImpactSprite(Vector3 source, Vector3 direction, float severity)
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: 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_0044: 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_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		if (!enableHitImpactSprites.Value || impactSpriteMaterials.Count == 0)
		{
			return;
		}
		EnsureBloodVisualRoot();
		Camera main = Camera.main;
		if (cameraSafeHitSprites.Value && (Object)(object)main != (Object)null)
		{
			Vector3 val = source - ((Component)main).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude < 0.48f)
			{
				return;
			}
		}
		GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
		((Object)obj).name = "YoureInjured_HitBloodSprite";
		obj.transform.SetParent(bloodVisualRoot, true);
		obj.transform.position = source + direction * 0.045f;
		obj.transform.localScale = Vector3.one * Mathf.Lerp(0.2f, Mathf.Max(0.2f, hitImpactSpriteMaximumSize.Value), severity);
		Collider component = obj.GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			Object.Destroy((Object)(object)component);
		}
		Renderer component2 = obj.GetComponent<Renderer>();
		if ((Object)(object)component2 != (Object)null)
		{
			component2.sharedMaterial = impactSpriteMaterials[Random.Range(0, impactSpriteMaterials.Count)];
			component2.shadowCastingMode = (ShadowCastingMode)0;
			component2.receiveShadows = false;
		}
		obj.AddComponent<BloodImpactSprite>().Initialize(direction * Mathf.Lerp(0.45f, 1.1f, severity), Mathf.Clamp(hitImpactSpriteLifetime.Value, 0.06f, 0.3f), component2);
	}

	private void SpawnBloodDroplet(Transform owner, Vector3 source, Vector3 initialVelocity, float size, float lifetime, bool trailDrop, bool createSplatWhenLanding)
	{
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: 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_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		if (enableBleedingVisuals.Value)
		{
			EnsureBloodVisualRoot();
			bool flag = trailDrop && dripSpriteMaterials.Count > 0;
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)(flag ? 5 : 0));
			((Object)val).name = (flag ? "YoureInjured_BloodDripSprite" : "YoureInjured_BloodDroplet");
			val.transform.SetParent(bloodVisualRoot, true);
			val.transform.position = source;
			val.transform.localScale = (Vector3)(flag ? new Vector3(Mathf.Max(0.026f, size * 2.5f), Mathf.Max(0.026f, size * 2.5f), 1f) : (Vector3.one * Mathf.Max(0.018f, size)));
			Camera main = Camera.main;
			if (flag && (Object)(object)main != (Object)null)
			{
				val.transform.rotation = ((Component)main).transform.rotation;
			}
			Collider component = val.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = val.GetComponent<Renderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.sharedMaterial = (flag ? dripSpriteMaterials[Random.Range(0, dripSpriteMaterials.Count)] : GetBloodDropMaterial());
				component2.shadowCastingMode = (ShadowCastingMode)0;
				component2.receiveShadows = false;
			}
			val.AddComponent<BloodDroplet>().Initialize(this, owner, initialVelocity, Mathf.Max(0.2f, lifetime), Mathf.Max(1f, bloodDropletGravity.Value), trailDrop, createSplatWhenLanding);
		}
	}

	internal void LandBloodDroplet(Vector3 point, Vector3 normal, bool trailDrop)
	{
		//IL_0000: 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_0012: Unknown result type (might be due to invalid IL or missing references)
		if (!(normal.y < 0.18f))
		{
			CreateGroundBloodSplat(point, ((Vector3)(ref normal)).normalized, trailDrop);
		}
	}

	internal bool TryLandBloodAtFallback(Transform owner, Vector3 source, bool trailDrop)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)owner == (Object)null || (Object)(object)owner != (Object)(object)((Component)localPlayer).transform)
		{
			return false;
		}
		bool num = TryPlaceBloodOnGround(localPlayer, source, trailDrop);
		if (num)
		{
			dropletFallbackLandings++;
		}
		return num;
	}

	private bool TryPlaceBloodOnGround(Player player, Vector3 source, bool trailDrop)
	{
		//IL_0002: 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)
		if (!TryFindGroundBelow(player, source, out var point, out var normal))
		{
			groundProbeFailures++;
			return false;
		}
		groundProbeSuccesses++;
		CreateGroundBloodSplat(point, normal, trailDrop);
		return true;
	}

	private bool TryFindGroundBelow(Player player, Vector3 source, out Vector3 point, out Vector3 normal)
	{
		//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_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: 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_0023: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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)
		//IL_0112: 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_011c: 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_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: 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_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//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_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		point = Vector3.zero;
		normal = Vector3.up;
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		RaycastHit[] array = Physics.RaycastAll(source + Vector3.up * 1.8f, Vector3.down, 7f, -1, (QueryTriggerInteraction)1);
		float num = float.MaxValue;
		Vector3 val;
		for (int i = 0; i < array.Length; i++)
		{
			Collider collider = ((RaycastHit)(ref array[i])).collider;
			if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)player).transform) && !(((RaycastHit)(ref array[i])).normal.y < 0.18f) && !(((RaycastHit)(ref array[i])).distance >= num))
			{
				num = ((RaycastHit)(ref array[i])).distance;
				point = ((RaycastHit)(ref array[i])).point;
				val = ((RaycastHit)(ref array[i])).normal;
				normal = ((Vector3)(ref val)).normalized;
			}
		}
		if (num < float.MaxValue)
		{
			return true;
		}
		Collider lastGroundCollider = ((Character)player).GetLastGroundCollider();
		Vector3 lastGroundNormal = ((Character)player).GetLastGroundNormal();
		if ((Object)(object)lastGroundCollider != (Object)null && lastGroundNormal.y >= 0.18f)
		{
			Vector3 val2 = lastGroundCollider.ClosestPoint(((Component)player).transform.position + Vector3.up * 0.3f);
			val = val2 - ((Component)player).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude <= 36f)
			{
				point = val2;
				normal = ((Vector3)(ref lastGroundNormal)).normalized;
				return true;
			}
		}
		return false;
	}

	private void CreateGroundBloodSplat(Vector3 point, Vector3 normal, bool trailDrop)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Expected O, but got Unknown
		//IL_0090: 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_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_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: 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_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		if (!enableBleedingVisuals.Value)
		{
			return;
		}
		CleanupDeadBloodSplats();
		int num = Mathf.Max(10, maximumGroundBloodSplats.Value);
		while (activeGroundBlood.Count >= num)
		{
			GroundBloodSplat groundBloodSplat = activeGroundBlood[0];
			activeGroundBlood.RemoveAt(0);
			if ((Object)(object)groundBloodSplat != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)groundBloodSplat).gameObject);
			}
		}
		EnsureBloodVisualRoot();
		GameObject val = new GameObject("YoureInjured_LiquidGroundBlood");
		val.transform.SetParent(bloodVisualRoot, true);
		val.transform.position = point + normal * 0.011f;
		val.transform.rotation = Quaternion.FromToRotation(Vector3.up, normal);
		float num2 = Mathf.Max(0.03f, bloodSplatMinimumSize.Value);
		float num3 = Mathf.Max(num2, bloodSplatMaximumSize.Value);
		float num4 = (trailDrop ? Random.Range(Mathf.Lerp(num2, num3, 0.25f), Mathf.Lerp(num2, num3, 0.76f)) : Random.Range(Mathf.Lerp(num2, num3, 0.5f), num3));
		float aspect = (trailDrop ? Random.Range(0.55f, 2.25f) : Random.Range(0.72f, 1.95f));
		float yaw = Random.Range(0f, 360f);
		List<Mesh> list = new List<Mesh>();
		CreateBloodDecalMesh(val.transform, "YoureInjured_LiquidBloodPool", Vector3.zero, num4, aspect, yaw, 4, 0f, GetBloodLiquidMaterial(Random.Range(0, 7)), list);
		int num5 = (trailDrop ? Random.Range(1, 4) : Random.Range(2, 5));
		for (int i = 0; i < num5; i++)
		{
			float num6 = Random.Range(0f, (float)Math.PI * 2f);
			Vector3 val2 = new Vector3(Mathf.Cos(num6), 0f, Mathf.Sin(num6));
			float num7 = num4 * Random.Range(0.48f, trailDrop ? 0.82f : 1.2f);
			Vector3 localPosition = val2 * num7 + Vector3.up * 0.0015f;
			CreateBloodDecalMesh(val.transform, "YoureInjured_LiquidBloodDrop", localPosition, num4 * Random.Range(0.11f, 0.28f), Random.Range(0.5f, 1.75f), Random.Range(0f, 360f), 4, 0f, GetBloodLiquidMaterial(Random.Range(0, 7)), list);
		}
		GroundBloodSplat groundBloodSplat2 = val.AddComponent<GroundBloodSplat>();
		groundBloodSplat2.Initialize(this, Mathf.Max(5f, groundBloodLifetimeSeconds.Value), Mathf.Clamp(bloodLiquidSpreadSeconds.Value, 0.1f, 2f), list);
		activeGroundBlood.Add(groundBloodSplat2);
		groundBloodSplatsSpawned++;
	}

	private static void CreateBloodDecalMesh(Transform parent, string name, Vector3 localPosition, float diameter, float aspect, float yaw, int edgeCount, float irregularity, Material material, List<Mesh> ownedMeshes)
	{
		//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_0013: 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_001f: 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_002c: 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)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name);
		val.transform.SetParent(parent, false);
		val.transform.localPosition = localPosition;
		val.transform.localRotation = Quaternion.AngleAxis(yaw, Vector3.up);
		val.transform.localScale = new Vector3(Mathf.Max(0.01f, diameter * aspect), 1f, Mathf.Max(0.01f, diameter / Mathf.Max(0.05f, aspect)));
		MeshFilter val2 = val.AddComponent<MeshFilter>();
		MeshRenderer obj = val.AddComponent<MeshRenderer>();
		Mesh item = (val2.sharedMesh = BuildIrregularBloodMesh(edgeCount, irregularity));
		((Renderer)obj).sharedMaterial = material;
		((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)obj).receiveShadows = false;
		ownedMeshes?.Add(item);
	}

	private static Mesh BuildIrregularBloodMesh(int requestedEdgeCount, float irregularity)
	{
		//IL_0017: 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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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_0052: 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_006d: 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_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: 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_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: 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_00d7: 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)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: 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_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: 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_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Expected O, but got Unknown
		Vector3[] vertices = (Vector3[])(object)new Vector3[4]
		{
			new Vector3(-0.5f, 0f, -0.5f),
			new Vector3(-0.5f, 0f, 0.5f),
			new Vector3(0.5f, 0f, 0.5f),
			new Vector3(0.5f, 0f, -0.5f)
		};
		Vector3[] normals = (Vector3[])(object)new Vector3[4]
		{
			Vector3.up,
			Vector3.up,
			Vector3.up,
			Vector3.up
		};
		Vector2[] uv = (Vector2[])(object)new Vector2[4]
		{
			new Vector2(0f, 0f),
			new Vector2(0f, 1f),
			new Vector2(1f, 1f),
			new Vector2(1f, 0f)
		};
		int[] triangles = new int[6] { 0, 1, 2, 0, 2, 3 };
		Mesh val = new Mesh
		{
			name = "YoureInjured_LiquidBloodDecalQuad",
			vertices = vertices,
			normals = normals,
			uv = uv,
			triangles = triangles
		};
		val.RecalculateBounds();
		return val;
	}

	internal void UnregisterGroundBlood(GroundBloodSplat splat)
	{
		activeGroundBlood.Remove(splat);
	}

	private void CleanupDeadBloodSplats()
	{
		for (int num = activeGroundBlood.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)activeGroundBlood[num] == (Object)null)
			{
				activeGroundBlood.RemoveAt(num);
			}
		}
	}

	private void EnsureBloodVisualRoot()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		if (!((Object)(object)bloodVisualRoot != (Object)null))
		{
			GameObject val = new GameObject("YoureInjured_BloodVisuals");
			bloodVisualRoot = val.transform;
		}
	}

	private void LoadExternalImpactSprites()
	{
		string text = Path.Combine(pluginDirectory ?? string.Empty, "assets", "bleeding", "impact_frames");
		if (!Directory.Exists(text))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: no impact-sprite folder found at " + text + ". Hit droplets will still work."));
			return;
		}
		string[] files;
		try
		{
			files = Directory.GetFiles(text, "*.png", SearchOption.TopDirectoryOnly);
			Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: could not enumerate impact sprite files. " + ex.Message));
			return;
		}
		int num = Mathf.Clamp(maximumImpactSpriteTextures.Value, 1, 12);
		for (int i = 0; i < files.Length; i++)
		{
			if (impactSpriteTextures.Count >= num)
			{
				break;
			}
			if (!InjuryAssetLoader.TryLoadAlphaMaskPng(files[i], out var texture, out var error))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: skipped impact sprite " + Path.GetFileName(files[i]) + ". " + error));
				continue;
			}
			((Object)texture).name = "YoureInjured_ImpactSprite_" + Path.GetFileNameWithoutExtension(files[i]);
			impactSpriteTextures.Add(texture);
			impactSpriteMaterials.Add(CreateImpactSpriteMaterial(texture));
		}
		string path = Path.Combine(pluginDirectory ?? string.Empty, "assets", "bleeding", "drip_frames");
		if (Directory.Exists(path))
		{
			try
			{
				string[] files2 = Directory.GetFiles(path, "*.png", SearchOption.TopDirectoryOnly);
				Array.Sort(files2, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
				for (int j = 0; j < files2.Length; j++)
				{
					if (dripSpriteTextures.Count >= 4)
					{
						break;
					}
					if (!InjuryAssetLoader.TryLoadAlphaMaskPng(files2[j], out var texture2, out var error2))
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: skipped drip sprite " + Path.GetFileName(files2[j]) + ". " + error2));
						continue;
					}
					((Object)texture2).name = "YoureInjured_DripSprite_" + Path.GetFileNameWithoutExtension(files2[j]);
					dripSpriteTextures.Add(texture2);
					dripSpriteMaterials.Add(CreateImpactSpriteMaterial(texture2));
				}
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: could not enumerate drip sprite files. " + ex2.Message));
			}
		}
		if (impactSpriteMaterials.Count > 0 || dripSpriteMaterials.Count > 0)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Injured: loaded " + impactSpriteMaterials.Count + " camera-safe impact sprites and " + dripSpriteMaterials.Count + " falling drip sprites."));
		}
	}

	private static Material CreateImpactSpriteMaterial(Texture2D texture)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		Shader val = Shader.Find("Unlit/Transparent");
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Sprites/Default");
		}
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Legacy Shaders/Transparent/Diffuse");
		}
		Material val2 = new Material(val);
		val2.mainTexture = (Texture)(object)texture;
		if (val2.HasProperty("_Color"))
		{
			val2.SetColor("_Color", new Color(0.4f, 0.01f, 0.016f, 0.78f));
		}
		val2.renderQueue = 3002;
		return val2;
	}

	private IEnumerator LoadHitAudioFiles()
	{
		yield return ((MonoBehaviour)this).StartCoroutine(LoadExternalMp3(Path.Combine(pluginDirectory ?? string.Empty, "assets", "audio", axeHitAudioFile.Value.Trim()), delegate(object clip)
		{
			axeHitAudioClip = clip;
		}, "axe hit"));
		yield return ((MonoBehaviour)this).StartCoroutine(LoadExternalMp3(Path.Combine(pluginDirectory ?? string.Empty, "assets", "audio", swordHitAudioFile.Value.Trim()), delegate(object clip)
		{
			swordHitAudioClip = clip;
		}, "sword hit"));
		yield return ((MonoBehaviour)this).StartCoroutine(LoadExternalMp3(Path.Combine(pluginDirectory ?? string.Empty, "assets", "audio", arrowHitAudioFile.Value.Trim()), delegate(object clip)
		{
			arrowHitAudioClip = clip;
		}, "arrow hit"));
		yield return ((MonoBehaviour)this).StartCoroutine(LoadExternalMp3(Path.Combine(pluginDirectory ?? string.Empty, "assets", "audio", bandageAudioFile.Value.Trim()), delegate(object clip)
		{
			bandageAudioClip = clip;
		}, "bandage wrap"));
	}

	private IEnumerator LoadExternalMp3(string path, Action<object> onLoaded, string label)
	{
		object request;
		object operation;
		if (string.IsNullOrEmpty(path) || !File.Exists(path))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: " + label + " audio file was not found at " + path));
		}
		else if (TryBeginExternalMp3Request(path, label, out request, out operation))
		{
			yield return operation;
			CompleteExternalMp3Request(request, onLoaded, label);
		}
	}

	private bool TryBeginExternalMp3Request(string path, string label, out object request, out object operation)
	{
		request = null;
		operation = null;
		try
		{
			Type type = FindRuntimeType("UnityEngine.Networking.UnityWebRequestMultimedia");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: UnityWebRequestMultimedia was unavailable; could not load " + label + " audio."));
				return false;
			}
			MethodInfo methodInfo = null;
			MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2.Name == "GetAudioClip" && methodInfo2.GetParameters().Length == 2)
				{
					methodInfo = methodInfo2;
					break;
				}
			}
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: no compatible GetAudioClip method was found for " + label + " audio."));
				return false;
			}
			object obj = Enum.Parse(methodInfo.GetParameters()[1].ParameterType, "MPEG");
			request = methodInfo.Invoke(null, new object[2]
			{
				new Uri(path).AbsoluteUri,
				obj
			});
			if (request == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: could not create the request for " + label + " audio."));
				return false;
			}
			MethodInfo method = request.GetType().GetMethod("SendWebRequest", Type.EmptyTypes);
			if (method == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: no SendWebRequest method was found for " + label + " audio."));
				DisposeRequest(request);
				request = null;
				return false;
			}
			operation = method.Invoke(request, null);
			if (operation == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: SendWebRequest returned no operation for " + label + " audio."));
				DisposeRequest(request);
				request = null;
				return false;
			}
			return true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: could not start loading " + label + " audio. " + ex.Message));
			DisposeRequest(request);
			request = null;
			operation = null;
			return false;
		}
	}

	private void CompleteExternalMp3Request(object request, Action<object> onLoaded, string label)
	{
		try
		{
			if (request == null)
			{
				return;
			}
			PropertyInfo property = request.GetType().GetProperty("error", BindingFlags.Instance | BindingFlags.Public);
			string text = ((property != null) ? (property.GetValue(request, null) as string) : null);
			if (!string.IsNullOrEmpty(text))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: failed to load " + label + " audio. " + text));
				return;
			}
			PropertyInfo property2 = request.GetType().GetProperty("downloadHandler", BindingFlags.Instance | BindingFlags.Public);
			object obj = ((property2 != null) ? property2.GetValue(request, null) : null);
			PropertyInfo propertyInfo = obj?.GetType().GetProperty("audioClip", BindingFlags.Instance | BindingFlags.Public);
			object obj2 = ((propertyInfo != null) ? propertyInfo.GetValue(obj, null) : null);
			if (obj2 == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: the " + label + " MP3 decoded without an AudioClip."));
				return;
			}
			onLoaded?.Invoke(obj2);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Injured: loaded " + label + " audio from " + Path.GetFileName(GetRequestUrl(request)) + "."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: could not finish loading " + label + " audio. " + ex.Message));
		}
		finally
		{
			DisposeRequest(request);
		}
	}

	private static string GetRequestUrl(object request)
	{
		if (request == null)
		{
			return string.Empty;
		}
		try
		{
			PropertyInfo property = request.GetType().GetProperty("url", BindingFlags.Instance | BindingFlags.Public);
			string text = ((property != null) ? (property.GetValue(request, null) as string) : null);
			return string.IsNullOrEmpty(text) ? string.Empty : text;
		}
		catch
		{
			return string.Empty;
		}
	}

	private static void DisposeRequest(object request)
	{
		if (request is IDisposable disposable)
		{
			disposable.Dispose();
		}
	}

	private void TryPlayBandageAudio()
	{
		if (enableBandageAudio != null && enableBandageAudio.Value && bandageAudioClip != null)
		{
			TryPlayOneShot(bandageAudioClip, Mathf.Clamp01(bandageAudioVolume.Value));
		}
	}

	private void TryPlayHitAudio(HitData hit)
	{
		if (enableHitAudio == null || !enableHitAudio.Value || hit == null)
		{
			return;
		}
		HitSoundKind hitSoundKind = ResolveHitSoundKind(hit);
		if (hitSoundKind != HitSoundKind.None && !(Time.unscaledTime < nextAllowedRecognizedHitAudioTime))
		{
			object obj = null;
			switch (hitSoundKind)
			{
			case HitSoundKind.Axe:
				obj = axeHitAudioClip;
				break;
			case HitSoundKind.Arrow:
				obj = arrowHitAudioClip;
				break;
			case HitSoundKind.Sword:
				obj = swordHitAudioClip;
				break;
			}
			if (obj != null && TryPlayOneShot(obj, Mathf.Clamp01(hitAudioVolume.Value)))
			{
				float num = ((hitAudioCooldownSeconds == null) ? 0.18f : hitAudioCooldownSeconds.Value);
				nextAllowedRecognizedHitAudioTime = Time.unscaledTime + Mathf.Clamp(num, 0.05f, 1f);
			}
		}
	}

	private HitSoundKind ResolveHitSoundKind(HitData hit)
	{
		string text = ResolveHitAttackerName(hit).ToLowerInvariant();
		string text2 = ResolveHitSkillName(hit).ToLowerInvariant();
		if (text.Contains("arrow") || text.Contains("bow") || text2.Contains("bow"))
		{
			return HitSoundKind.Arrow;
		}
		if (text.Contains("draugr") && !text.Contains("elite"))
		{
			return HitSoundKind.Axe;
		}
		if (text.Contains("draugr_elite") || text.Contains("draugr elite") || text.Contains("skeleton"))
		{
			return HitSoundKind.Sword;
		}
		return HitSoundKind.None;
	}

	private static string ResolveHitAttackerName(HitData hit)
	{
		object hitAttackerObject = GetHitAttackerObject(hit);
		if (hitAttackerObject == null)
		{
			return string.Empty;
		}
		GameObject val = ResolveAttackerGameObject(hitAttackerObject);
		if ((Object)(object)val != (Object)null)
		{
			string obj = ((Object)val).name ?? string.Empty;
			Transform val2 = (((Object)(object)val.transform != (Object)null) ? val.transform.root : null);
			string text = (((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject != (Object)null) ? ((Object)((Component)val2).gameObject).name : string.Empty);
			return obj + " " + text;
		}
		return string.Empty;
	}

	private static object GetHitAttackerObject(HitData hit)
	{
		try
		{
			MethodInfo method = ((object)hit).GetType().GetMethod("GetAttacker", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
			return (method != null) ? method.Invoke(hit, null) : null;
		}
		catch
		{
			return null;
		}
	}

	private static GameObject ResolveAttackerGameObject(object attacker)
	{
		GameObject val = (GameObject)((attacker is GameObject) ? attacker : null);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		Component val2 = (Component)((attacker is Component) ? attacker : null);
		if ((Object)(object)val2 != (Object)null)
		{
			return val2.gameObject;
		}
		try
		{
			Type typeFromHandle = typeof(ZNetScene);
			FieldInfo field = typeFromHandle.GetField("instance", BindingFlags.Static | BindingFlags.Public);
			object obj = ((field != null) ? field.GetValue(null) : null);
			if (obj == null)
			{
				PropertyInfo property = typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
				obj = ((property != null) ? property.GetValue(null, null) : null);
			}
			if (obj == null)
			{
				return null;
			}
			MethodInfo[] methods = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "FindInstance")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 1 && parameters[0].ParameterType.IsInstanceOfType(attacker))
				{
					object obj2 = methodInfo.Invoke(obj, new object[1] { attacker });
					GameObject val3 = (GameObject)((obj2 is GameObject) ? obj2 : null);
					if ((Object)(object)val3 != (Object)null)
					{
						return val3;
					}
					Component val4 = (Component)((obj2 is Component) ? obj2 : null);
					if ((Object)(object)val4 != (Object)null)
					{
						return val4.gameObject;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static string ResolveHitSkillName(HitData hit)
	{
		try
		{
			FieldInfo field = ((object)hit).GetType().GetField("m_skill", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			object obj = ((field != null) ? field.GetValue(hit) : null);
			return (obj != null) ? obj.ToString() : string.Empty;
		}
		catch
		{
			return string.Empty;
		}
	}

	private bool TryPlayOneShot(object clip, float volume)
	{
		if (clip == null)
		{
			return false;
		}
		Component val = EnsureHitAudioSource();
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo[] methods = ((object)val).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == "PlayOneShot" && methodInfo.GetParameters().Length == 2)
				{
					methodInfo.Invoke(val, new object[2] { clip, volume });
					return true;
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Injured: failed to play external audio. " + ex.Message));
		}
		return false;
	}

	private Component EnsureHitAudioSource()
	{
		if ((Object)(object)hitAudioSource != (Object)null)
		{
			return hitAudioSource;
		}
		Type type = FindRuntimeType("UnityEngine.AudioSource");
		if (type == null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"You're Injured: Unity AudioSource was unavailable.");
			return null;
		}
		hitAudioSource = ((Component)this).gameObject.GetComponent(type);
		if ((Object)(object)hitAudioSource == (Object)null)
		{
			hitAudioSource = ((Component)this).gameObject.AddComponent(type);
		}
		if ((Object)(object)hitAudioSource != (Object)null)
		{
			SetAudioProperty(hitAudioSource, "playOnAwake", false);
			SetAudioProperty(hitAudioSource, "spatialBlend", 0f);
			SetAudioProperty(hitAudioSource, "loop", false);
		}
		return hitAudioSource;
	}

	private static void SetAudioProperty(Component source, string name, object value)
	{
		if (!((Object)(object)source == (Object)null))
		{
			PropertyInfo property = ((object)source).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
			if (property != null && property.CanWrite)
			{
				property.SetValue(source, value, null);
			}
		}
	}

	private static Type FindRuntimeType(string fullName)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			Type type = assemblies[i].GetType(fullName, throwOnError: false);
			if (type != null)
			{
				return type;
			}
		}
		string text = null;
		if (string.Equals(fullName, "UnityEngine.AudioSource", StringComparison.Ordinal))
		{
			text = "UnityEngine.AudioModule";
		}
		else if (fullName.StartsWith("UnityEngine.Networking.", StringComparison.Ordinal))
		{
			text = "UnityEngine.UnityWebRequestAudioModule";
		}
		if (!string.IsNullOrEmpty(text))
		{
			try
			{
				Assembly assembly = Assembly.Load(text);
				Type type2 = ((assembly != null) ? assembly.GetType(fullName, throwOnError: false) : null);
				if (type2 != null)
				{
					return type2;
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private Material GetBloodDropMaterial()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)bloodDropMaterial == (Object)null)
		{
			bloodDropMaterial = CreateBloodMaterial(new Color(0.38f, 0.003f, 0.008f, 1f), 0.62f, transparent: false, 0.006f);
		}
		return bloodDropMaterial;
	}

	private Material GetBloodLiquidMaterial(int requestedVariant)
	{
		EnsureBloodLiquidMaterials();
		if (bloodLiquidMaterials == null || bloodLiquidMaterials.Length == 0)
		{
			return GetBloodDropMaterial();
		}
		int num = Mathf.Abs(requestedVariant) % bloodLiquidMaterials.Length;
		return bloodLiquidMaterials[num];
	}

	private void EnsureBloodLiquidMaterials()
	{
		if (bloodLiquidMaterials == null || bloodLiquidMaterials.Length != 7)
		{
			DestroyBloodLiquidMaterials();
			bloodLiquidMaterials = (Material[])(object)new Material[7];
			bloodLiquidTextures = (Texture2D[])(object)new Texture2D[7];
			for (int i = 0; i < 7; i++)
			{
				Texture2D val = CreateLiquidBloodTexture(i);
				bloodLiquidTextures[i] = val;
				bloodLiquidMaterials[i] = CreateLiquidBloodDecalMaterial(val);
			}
		}
	}

	private static Material CreateLiquidBloodDecalMaterial(Texture2D texture)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Expected O, but got Unknown
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		Shader val = Shader.Find("Standard");
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Legacy Shaders/Transparent/Diffuse");
		}
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Unlit/Transparent");
		}
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Sprites/Default");
		}
		Material val2 = new Material(val);
		val2.mainTexture = (Texture)(object)texture;
		if (val2.HasProperty("_Color"))
		{
			val2.SetColor("_Color", Color.white);
		}
		if (val2.HasProperty("_Glossiness"))
		{
			val2.SetFloat("_Glossiness", 0.93f);
		}
		if (val2.HasProperty("_Metallic"))
		{
			val2.SetFloat("_Metallic", 0f);
		}
		if (val2.HasProperty("_Mode"))
		{
			val2.SetFloat("_Mode", 3f);
			val2.SetInt("_SrcBlend", 5);
			val2.SetInt("_DstBlend", 10);
			val2.SetInt("_ZWrite", 0);
			val2.DisableKeyword("_ALPHATEST_ON");
			val2.EnableKeyword("_ALPHABLEND_ON");
			val2.DisableKeyword("_ALPHAPREMULTIPLY_ON");
		}
		val2.renderQueue = 3001;
		return val2;
	}

	private static Texture2D CreateLiquidBloodTexture(int variant)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Expected O, but got Unknown
		//IL_0290: 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_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(