using System;
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 BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BleedingMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2237482c32b5703c2199e5a28b625bd946339c16")]
[assembly: AssemblyProduct("BleedingMod")]
[assembly: AssemblyTitle("BleedingMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BleedingMod
{
[HarmonyPatch(typeof(CharacterMovement), "GetMovementForce")]
internal static class CharacterMovement_GetMovementForce_Patch
{
[HarmonyPostfix]
private static void Postfix(CharacterMovement __instance, ref float __result)
{
if (__result <= 0f || (Object)(object)__instance == (Object)null)
{
return;
}
Character component = ((Component)__instance).GetComponent<Character>();
if (!((Object)(object)component == (Object)null))
{
BleedingTracker component2 = ((Component)component).GetComponent<BleedingTracker>();
if (!((Object)(object)component2 == (Object)null) && component2.isBleeding && component2.level >= BleedLevel.Heavy)
{
__result *= 0.85f;
}
}
}
}
public class BleedingTracker : MonoBehaviour
{
public static BleedingTracker LocalInstance;
public static bool s_isBleeding = false;
public static BleedLevel s_level = BleedLevel.None;
public static float s_bleedStart = -999f;
public static bool s_isFading = false;
public static float s_fadeStart = -999f;
public const float FADE_DURATION = 1.6f;
private float _peakFallSpeed;
private bool _wasFalling;
private Character _char;
private Rigidbody _rb;
private BloodTrail _trail;
private const float REAL_DAMAGE_CHECK_DELAY = 0.35f;
private float _pendingCheckAt = -1f;
private float _preFallInjury = -1f;
private BleedLevel _pendingLevel;
public bool isBleeding
{
get
{
return s_isBleeding;
}
set
{
s_isBleeding = value;
}
}
public BleedLevel level
{
get
{
return s_level;
}
set
{
s_level = value;
}
}
public float bleedStart
{
get
{
return s_bleedStart;
}
set
{
s_bleedStart = value;
}
}
public static float FadeAlpha
{
get
{
if (s_isBleeding)
{
return 1f;
}
if (!s_isFading)
{
return 0f;
}
float num = (Time.time - s_fadeStart) / 1.6f;
return Mathf.Clamp01(1f - num);
}
}
private void Awake()
{
_char = ((Component)this).GetComponent<Character>();
_rb = ((Component)this).GetComponentInChildren<Rigidbody>();
_trail = ((Component)this).gameObject.GetComponent<BloodTrail>() ?? ((Component)this).gameObject.AddComponent<BloodTrail>();
}
private void Update()
{
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_char == (Object)null || (Object)(object)Character.localCharacter != (Object)(object)_char)
{
return;
}
LocalInstance = this;
if (s_isBleeding && Time.time - s_bleedStart >= BleedingPlugin.GetBleedDuration(s_level))
{
CureBleeding();
}
if (s_isFading && Time.time - s_fadeStart >= 1.6f)
{
s_isFading = false;
s_level = BleedLevel.None;
}
if ((Object)(object)_rb == (Object)null)
{
return;
}
if (SpiderCheck.IsGrabbedBySpider(_char))
{
_wasFalling = false;
_peakFallSpeed = 0f;
return;
}
bool flag;
try
{
flag = !GameHandler.IsInGameplayScene;
}
catch
{
flag = false;
}
if (flag)
{
_wasFalling = false;
_peakFallSpeed = 0f;
return;
}
float y = _rb.linearVelocity.y;
bool flag2 = false;
try
{
flag2 = (Object)(object)_char != (Object)null && (Object)(object)_char.data != (Object)null && _char.data.isGrounded;
}
catch
{
}
if (y < -4f)
{
_wasFalling = true;
_peakFallSpeed = Mathf.Max(_peakFallSpeed, 0f - y);
}
else if (_wasFalling && flag2)
{
float fallH = _peakFallSpeed * _peakFallSpeed / 19.62f;
BleedLevel bleedLevel = BleedingPlugin.ClassifyFall(fallH);
if (bleedLevel != BleedLevel.None)
{
StartBleed(bleedLevel, fallH);
}
_wasFalling = false;
_peakFallSpeed = 0f;
}
else if (_wasFalling && y > -2f && !flag2)
{
_wasFalling = false;
_peakFallSpeed = 0f;
}
}
private void StartBleed(BleedLevel lv, float fallH)
{
if (!s_isBleeding || lv > s_level)
{
s_bleedStart = Time.time;
s_isBleeding = true;
s_level = lv;
BleedingPlugin.Instance?.TriggerHurtEffect(_char);
ManualLogSource logger = BleedingPlugin.Logger;
if (logger != null)
{
logger.LogInfo((object)string.Format("[Bleeding] {0} → {1}", (fallH > 0f) ? $"Fall {fallH:F1}m" : "confirmed by injury", lv));
}
}
}
private float GetInjury()
{
if ((Object)(object)_char == (Object)null || _char.refs == null || (Object)(object)_char.refs.afflictions == (Object)null)
{
return 0f;
}
try
{
return _char.refs.afflictions.GetCurrentStatus((STATUSTYPE)0);
}
catch
{
return 0f;
}
}
public void CureBleeding()
{
if (s_isBleeding || s_isFading)
{
s_isBleeding = false;
s_bleedStart = -999f;
s_isFading = true;
s_fadeStart = Time.time;
}
}
}
public class BloodPool : MonoBehaviour
{
private const float GROW_DURATION = 15f;
private const float MIN_SCALE = 0.35f;
private const float MAX_SCALE = 1.9f;
private const float LIFETIME = 60f;
private static readonly Queue<BloodPool> _active = new Queue<BloodPool>();
private const int MAX_ACTIVE_POOLS = 12;
private float _age;
private MeshRenderer _mr;
private MaterialPropertyBlock _mpb;
public static void TrySpawn(Vector3 origin)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: 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_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
RaycastHit val = default(RaycastHit);
if (Physics.Raycast(origin + Vector3.up * 1.5f, Vector3.down, ref val, 4f, -1, (QueryTriggerInteraction)1) && (!((Object)(object)((RaycastHit)(ref val)).collider != (Object)null) || !((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>() != (Object)null)))
{
CreateAt(((RaycastHit)(ref val)).point, ((RaycastHit)(ref val)).normal);
}
}
private static void CreateAt(Vector3 pos, Vector3 normal)
{
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: 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)
//IL_00d1: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
Collider component = obj.GetComponent<Collider>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
((Object)obj).name = "BleedingMod_BloodPool";
MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
((Renderer)component2).receiveShadows = false;
((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
((Renderer)component2).lightProbeUsage = (LightProbeUsage)0;
((Renderer)component2).reflectionProbeUsage = (ReflectionProbeUsage)0;
Material val = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent"))
{
mainTexture = (Texture)(object)BleedingPlugin.Instance?.GetDropTexture()
};
val.SetColor("_Color", new Color(0.35f, 0.02f, 0.02f, 1f));
val.renderQueue = 3050;
((Renderer)component2).sharedMaterial = val;
Transform transform = obj.transform;
transform.position = pos + normal * 0.015f;
transform.rotation = Quaternion.LookRotation(-normal) * Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
transform.localScale = new Vector3(0.35f, 0.35f, 1f);
BloodPool item = obj.AddComponent<BloodPool>();
_active.Enqueue(item);
while (_active.Count > 12)
{
BloodPool bloodPool = _active.Dequeue();
if ((Object)(object)bloodPool != (Object)null)
{
Object.Destroy((Object)(object)((Component)bloodPool).gameObject);
}
}
}
private void Awake()
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
_mr = ((Component)this).GetComponent<MeshRenderer>();
_mpb = new MaterialPropertyBlock();
}
private void Update()
{
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
_age += Time.deltaTime;
if (_age >= 60f)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
float num = Mathf.Clamp01(_age / 15f);
float num2 = Mathf.Lerp(0.35f, 1.9f, num);
((Component)this).transform.localScale = new Vector3(num2, num2, 1f);
float num3 = ((_age > 55f) ? ((_age - 55f) / 5f) : 0f);
float num4 = 1f - num3;
if ((Object)(object)_mr != (Object)null)
{
((Renderer)_mr).GetPropertyBlock(_mpb);
_mpb.SetColor("_Color", new Color(0.35f, 0.02f, 0.02f, num4));
((Renderer)_mr).SetPropertyBlock(_mpb);
}
}
}
public class BloodTrail : MonoBehaviour
{
private const float MIN_SPEED_TO_DROP = 1.5f;
private const float RAY_LENGTH = 8f;
private const float DECAL_LIFT = 0.02f;
private const float RAY_UP_OFFSET = 2.5f;
private const float POOL_IDLE_TIME = 2f;
private const float POOL_COOLDOWN = 5f;
private static readonly Queue<BloodDrop> _activeDrops = new Queue<BloodDrop>();
private static Material _sharedMat;
private Character _char;
private Rigidbody _rb;
private float _distanceSinceLast;
private Vector3 _lastPos;
private bool _lastPosValid;
private float _idleTime;
private float _poolCooldown;
private AudioSource _audioSrc;
private AudioClip _dripClip;
private void Awake()
{
_char = ((Component)this).GetComponent<Character>();
_rb = ((Component)this).GetComponentInChildren<Rigidbody>();
EnsureAudio();
}
private void EnsureAudio()
{
if (!((Object)(object)_audioSrc != (Object)null))
{
_audioSrc = ((Component)this).gameObject.AddComponent<AudioSource>();
_audioSrc.playOnAwake = false;
_audioSrc.spatialBlend = 0f;
_audioSrc.volume = 0.35f;
_dripClip = GenerateDripClip();
}
}
private static AudioClip GenerateDripClip()
{
int num = 44100;
int num2 = num / 6;
float[] array = new float[num2];
float num3 = 220f;
for (int i = 0; i < num2; i++)
{
float num4 = (float)i / (float)num;
float num5 = Mathf.Exp((0f - num4) * 22f);
array[i] = Mathf.Sin(MathF.PI * 2f * num3 * num4) * num5 * 0.6f;
}
AudioClip obj = AudioClip.Create("TambiDrip", num2, 1, num, false);
obj.SetData(array, 0);
return obj;
}
private void Update()
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: 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_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_char == (Object)null || (Object)(object)Character.localCharacter != (Object)(object)_char || (BleedingPlugin.cfgEnableTrail != null && !BleedingPlugin.cfgEnableTrail.Value))
{
return;
}
BleedingTracker localInstance = BleedingTracker.LocalInstance;
if ((Object)(object)localInstance == (Object)null || !localInstance.isBleeding)
{
_lastPosValid = false;
_distanceSinceLast = 0f;
}
else
{
if ((Object)(object)_rb == (Object)null)
{
return;
}
Vector3 position = ((Component)_rb).transform.position;
if (_lastPosValid)
{
Vector3 val = position - _lastPos;
val.y = 0f;
_distanceSinceLast += ((Vector3)(ref val)).magnitude;
}
_lastPos = position;
_lastPosValid = true;
Vector2 val2 = new Vector2(_rb.linearVelocity.x, _rb.linearVelocity.z);
float magnitude = ((Vector2)(ref val2)).magnitude;
if (_poolCooldown > 0f)
{
_poolCooldown -= Time.deltaTime;
}
if (magnitude < 0.3f && localInstance.level >= BleedLevel.Heavy)
{
_idleTime += Time.deltaTime;
if (_idleTime >= 2f && _poolCooldown <= 0f)
{
BloodPool.TrySpawn(position);
_poolCooldown = 5f;
_idleTime = 0f;
}
}
else
{
_idleTime = 0f;
}
if (magnitude < 1.5f)
{
return;
}
float intervalMeters = GetIntervalMeters(localInstance.level);
if (_distanceSinceLast >= intervalMeters)
{
_distanceSinceLast = 0f;
SpawnDrop(position, localInstance.level);
if ((Object)(object)_audioSrc != (Object)null && (Object)(object)_dripClip != (Object)null && Random.value < 0.35f)
{
_audioSrc.PlayOneShot(_dripClip, 0.25f);
}
}
}
}
private static float GetIntervalMeters(BleedLevel level)
{
return level switch
{
BleedLevel.Light => 3.5f,
BleedLevel.Medium => 2.2f,
BleedLevel.Heavy => 1.2f,
BleedLevel.Massive => 0.7f,
_ => 3f,
};
}
private static float GetDropScale(BleedLevel level)
{
return level switch
{
BleedLevel.Light => 0.4f,
BleedLevel.Medium => 0.6f,
BleedLevel.Heavy => 0.85f,
BleedLevel.Massive => 1.1f,
_ => 0.5f,
};
}
private void SpawnDrop(Vector3 origin, BleedLevel level)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: 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_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: 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_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_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_016c: Unknown result type (might be due to invalid IL or missing references)
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
RaycastHit[] array = Physics.RaycastAll(origin + Vector3.up * 2.5f, Vector3.down, 8f, -1, (QueryTriggerInteraction)1);
if (array == null || array.Length == 0)
{
return;
}
Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
RaycastHit val = default(RaycastHit);
bool flag = false;
RaycastHit[] array2 = array;
for (int num = 0; num < array2.Length; num++)
{
RaycastHit val2 = array2[num];
if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Character>() != (Object)null))
{
val = val2;
flag = true;
break;
}
}
if (!flag)
{
return;
}
EnsureSharedMaterial();
if ((Object)(object)_sharedMat == (Object)null)
{
return;
}
GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
Collider component = obj.GetComponent<Collider>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
((Object)obj).name = "BleedingMod_BloodDrop";
MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
((Renderer)component2).sharedMaterial = _sharedMat;
((Renderer)component2).receiveShadows = false;
((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
((Renderer)component2).lightProbeUsage = (LightProbeUsage)0;
((Renderer)component2).reflectionProbeUsage = (ReflectionProbeUsage)0;
Transform transform = obj.transform;
transform.position = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * 0.02f;
transform.rotation = Quaternion.LookRotation(-((RaycastHit)(ref val)).normal) * Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
float num2 = GetDropScale(level) * Random.Range(0.85f, 1.15f);
transform.localScale = new Vector3(num2, num2, num2);
float lifetime = ((BleedingPlugin.cfgTrailLifetime != null) ? BleedingPlugin.cfgTrailLifetime.Value : 25f);
BloodDrop bloodDrop = obj.AddComponent<BloodDrop>();
bloodDrop.Init(lifetime);
_activeDrops.Enqueue(bloodDrop);
int num3 = ((BleedingPlugin.cfgMaxTrailDrops != null) ? BleedingPlugin.cfgMaxTrailDrops.Value : 40);
while (_activeDrops.Count > num3)
{
BloodDrop bloodDrop2 = _activeDrops.Dequeue();
if ((Object)(object)bloodDrop2 != (Object)null)
{
bloodDrop2.ForceFadeOut();
}
}
}
private static void EnsureSharedMaterial()
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Expected O, but got Unknown
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_sharedMat != (Object)null)
{
return;
}
Texture2D val = BleedingPlugin.Instance?.GetDropTexture();
if (!((Object)(object)val == (Object)null))
{
Shader val2 = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent") ?? Shader.Find("Legacy Shaders/Transparent/Diffuse");
if (!((Object)(object)val2 == (Object)null))
{
_sharedMat = new Material(val2)
{
mainTexture = (Texture)(object)val
};
_sharedMat.SetColor("_Color", new Color(0.55f, 0.02f, 0.02f, 1f));
_sharedMat.renderQueue = 3100;
}
}
}
}
public class BloodDrop : MonoBehaviour
{
private float _totalLife;
private float _elapsed;
private MaterialPropertyBlock _mpb;
private MeshRenderer _mr;
private Color _baseColor = new Color(0.55f, 0.02f, 0.02f, 1f);
public void Init(float lifetime)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
_totalLife = Mathf.Max(1f, lifetime);
_mr = ((Component)this).GetComponent<MeshRenderer>();
_mpb = new MaterialPropertyBlock();
}
public void ForceFadeOut()
{
_elapsed = _totalLife - 1f;
}
private void Update()
{
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
_elapsed += Time.deltaTime;
if (_elapsed >= _totalLife)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
float num = _elapsed / _totalLife;
float num2 = ((num < 0.75f) ? 1f : Mathf.Lerp(1f, 0f, (num - 0.75f) / 0.25f));
if ((Object)(object)_mr != (Object)null && _mpb != null)
{
((Renderer)_mr).GetPropertyBlock(_mpb);
_mpb.SetColor("_Color", new Color(_baseColor.r, _baseColor.g, _baseColor.b, num2));
((Renderer)_mr).SetPropertyBlock(_mpb);
}
}
}
[HarmonyPatch(typeof(Action_ModifyStatus), "RunAction")]
internal static class Patch_ModifyStatus_HealInjury
{
private static readonly FieldInfo _itemField = AccessTools.Field(typeof(ItemAction), "item") ?? AccessTools.Field(typeof(Action_ModifyStatus), "item");
[HarmonyPostfix]
private static void Postfix(Action_ModifyStatus __instance)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((int)__instance.statusType == 0 && !(__instance.changeAmount >= 0f))
{
object? obj = _itemField?.GetValue(__instance);
object? obj2 = ((obj is Item) ? obj : null);
Character val = ((obj2 != null) ? ((Item)obj2).holderCharacter : null);
if (!((Object)(object)val == (Object)null) && val.IsLocal)
{
((Component)val).GetComponent<BleedingTracker>()?.CureBleeding();
}
}
}
catch (Exception ex)
{
BleedingPlugin.Logger.LogWarning((object)("[Bleeding] ModifyStatus heal: " + ex.Message));
}
}
}
[BepInPlugin("com.tambistudios.bleeding", "Bleeding", "1.0.0")]
public class BleedingPlugin : BaseUnityPlugin
{
public const string MOD_GUID = "com.tambistudios.bleeding";
public const string MOD_NAME = "Bleeding";
public const string MOD_VERSION = "1.0.0";
public static BleedingPlugin Instance;
public static ManualLogSource Logger;
public const float BASE_THRESHOLD_LIGHT = 10f;
public const float BASE_THRESHOLD_MEDIUM = 20f;
public const float BASE_THRESHOLD_HEAVY = 30f;
public const float DURATION_LIGHT = 15f;
public const float DURATION_MEDIUM = 30f;
public const float DURATION_HEAVY = 60f;
public const float DURATION_MASSIVE = 120f;
public const float HARDCODED_MASSIVE_HEIGHT = 160f;
public static ConfigEntry<bool> cfgEnableTrail;
public static ConfigEntry<float> cfgTrailLifetime;
public static ConfigEntry<int> cfgMaxTrailDrops;
public static ConfigEntry<float> cfgOverlayIntensity;
public const float HARDCODED_LIGHT_HEIGHT = 32f;
public const float HARDCODED_MEDIUM_HEIGHT = 64f;
public const float HARDCODED_HEAVY_HEIGHT = 96f;
public const bool HARDCODED_REQUIRE_REAL_FALL_DAMAGE = true;
public const float HARDCODED_MIN_INJURY_TO_BLEED = 0.02f;
private Texture2D _guiTex;
private Texture2D _dropTex;
private float _pulseTimer;
private float _flashTimer;
private static readonly MethodInfo _addIllegalStatus = typeof(Character).GetMethod("AddIllegalStatus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private void Awake()
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
cfgEnableTrail = ((BaseUnityPlugin)this).Config.Bind<bool>("Trail", "EnableBloodTrail", true, "Whether bleeding leaves blood drops on the ground while you move.");
cfgTrailLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Trail", "DropLifetimeSeconds", 25f, "How long each blood drop stays visible before fading (seconds).");
cfgMaxTrailDrops = ((BaseUnityPlugin)this).Config.Bind<int>("Trail", "MaxActiveDrops", 40, "Maximum number of blood drops on the ground at once. Older drops fade first.");
cfgOverlayIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ScreenOverlayIntensity", 1f, "Red screen overlay intensity while bleeding. Set 0 to disable for motion sickness comfort.");
new Harmony("com.tambistudios.bleeding").PatchAll();
Logger.LogInfo((object)"[Bleeding 1.0.0] Loaded.");
}
public static float GetScaledThreshold(BleedLevel level)
{
float num;
switch (TambiAfflictionOption.GetValue("Bleeding"))
{
case 0:
return -1f;
case 1:
num = 0.6f;
break;
case 2:
num = 1f;
break;
case 3:
num = 1.5f;
break;
default:
num = 1f;
break;
}
float num2 = num;
float num3 = level switch
{
BleedLevel.Light => 32f,
BleedLevel.Medium => 64f,
BleedLevel.Heavy => 96f,
BleedLevel.Massive => 160f,
_ => 64f,
};
if (num2 <= 0.6f)
{
return num3 * 1.5f;
}
if (num2 <= 1.5f)
{
return num3;
}
return num3 * 0.5f;
}
public static float GetBleedDuration(BleedLevel level)
{
return level switch
{
BleedLevel.Light => 15f,
BleedLevel.Medium => 30f,
BleedLevel.Heavy => 60f,
BleedLevel.Massive => 120f,
_ => 30f,
};
}
public static BleedLevel ClassifyFall(float fallH)
{
float scaledThreshold = GetScaledThreshold(BleedLevel.Massive);
float scaledThreshold2 = GetScaledThreshold(BleedLevel.Heavy);
float scaledThreshold3 = GetScaledThreshold(BleedLevel.Medium);
float scaledThreshold4 = GetScaledThreshold(BleedLevel.Light);
if (scaledThreshold > 0f && fallH >= scaledThreshold)
{
return BleedLevel.Massive;
}
if (scaledThreshold2 > 0f && fallH >= scaledThreshold2)
{
return BleedLevel.Heavy;
}
if (scaledThreshold3 > 0f && fallH >= scaledThreshold3)
{
return BleedLevel.Medium;
}
if (scaledThreshold4 > 0f && fallH >= scaledThreshold4)
{
return BleedLevel.Light;
}
return BleedLevel.None;
}
private void Update()
{
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter != (Object)null && (Object)(object)((Component)localCharacter).GetComponent<BleedingTracker>() == (Object)null)
{
((Component)localCharacter).gameObject.AddComponent<BleedingTracker>();
}
BleedingTracker localInstance = BleedingTracker.LocalInstance;
if ((Object)(object)localInstance != (Object)null && localInstance.isBleeding)
{
_pulseTimer += Time.deltaTime * (0.8f + (float)localInstance.level * 0.25f);
}
else
{
_pulseTimer = 0f;
}
if (_flashTimer > 0f)
{
_flashTimer = Mathf.Max(0f, _flashTimer - Time.deltaTime);
}
}
internal void TriggerHurtEffect(Character local)
{
_flashTimer = 1f;
try
{
_addIllegalStatus?.Invoke(local, new object[2] { "Injury", 1f });
}
catch (Exception ex)
{
Logger.LogWarning((object)("[Bleeding] HurtEffect: " + ex.Message));
}
}
internal Texture2D GetDropTexture()
{
if ((Object)(object)_dropTex == (Object)null)
{
_dropTex = LoadDropTexture();
}
return _dropTex;
}
private static Texture2D LoadDropTexture()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
try
{
string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets", "blood.png");
if (File.Exists(path))
{
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
((Texture)val).filterMode = (FilterMode)1;
if (ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
{
return val;
}
}
}
catch (Exception ex)
{
Logger.LogWarning((object)("[Bleeding] LoadDropTexture: " + ex.Message));
}
return MakeDropTexture(64);
}
private static Texture2D MakeDropTexture(int size)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Expected O, but got Unknown
//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)
Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
((Texture)val).filterMode = (FilterMode)1;
((Texture)val).wrapMode = (TextureWrapMode)1;
float num = (float)size * 0.5f;
float num2 = (float)size * 0.42f;
float num3 = (float)size * 0.3f;
float num4 = (float)size * 0.94f;
Color32[] array = (Color32[])(object)new Color32[size * size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
float num5 = (float)j + 0.5f;
float num6 = (float)i + 0.5f;
float num7 = num5 - num;
float num8 = num6 - num2;
bool flag = num7 * num7 + num8 * num8 <= num3 * num3;
float num9 = ((num6 >= num2 && num6 <= num4) ? ((num4 - num6) / (num4 - num2) * num3) : 0f);
bool num10 = num6 > num2 && num6 <= num4 && Mathf.Abs(num5 - num) <= num9;
float num11 = Mathf.Clamp01(1f - (Mathf.Sqrt(num7 * num7 + num8 * num8) - num3 + 1.5f) / 1.5f);
byte b = (num10 ? byte.MaxValue : (flag ? byte.MaxValue : ((byte)(num11 * 255f))));
array[i * size + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
}
}
val.SetPixels32(array);
val.Apply();
return val;
}
private void OnGUI()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Expected O, but got Unknown
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
//IL_0215: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
if ((int)Event.current.type != 7)
{
return;
}
if ((Object)(object)_guiTex == (Object)null)
{
_guiTex = new Texture2D(1, 1);
_guiTex.SetPixel(0, 0, Color.white);
_guiTex.Apply();
}
Color color = GUI.color;
BleedingTracker localInstance = BleedingTracker.LocalInstance;
bool flag = (Object)(object)localInstance != (Object)null && localInstance.isBleeding;
bool flag2 = flag || BleedingTracker.s_isFading;
float fadeAlpha = BleedingTracker.FadeAlpha;
float num = Mathf.Clamp01((cfgOverlayIntensity != null) ? cfgOverlayIntensity.Value : 1f);
float num2 = _pulseTimer % 1f;
float num3 = ((num2 < 0.2f) ? (num2 / 0.2f) : (1f - (num2 - 0.2f) / 0.8f));
if (flag2 && num > 0.01f)
{
float num4 = BleedingTracker.s_level switch
{
BleedLevel.Light => 0.15f,
BleedLevel.Medium => 0.22f,
BleedLevel.Heavy => 0.32f,
BleedLevel.Massive => 0.45f,
_ => 0.2f,
} + (flag ? (num3 * 0.05f) : 0f);
GUI.color = new Color(0.6f, 0f, 0f, num4 * num * fadeAlpha);
GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_guiTex);
}
if (_flashTimer > 0f && num > 0.01f)
{
GUI.color = new Color(0.55f, 0f, 0f, _flashTimer * 0.5f * num);
GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_guiTex);
}
if (flag2)
{
Texture2D dropTexture = GetDropTexture();
if ((Object)(object)dropTexture != (Object)null)
{
GUI.color = new Color(0.75f, 0.06f, 0.06f, fadeAlpha);
GUI.DrawTexture(new Rect((float)Screen.width - 112f, 16f, 96f, 96f), (Texture)(object)dropTexture);
}
}
GUI.color = color;
}
}
public enum BleedLevel
{
None,
Light,
Medium,
Heavy,
Massive
}
[HarmonyPatch(typeof(Character), "Awake")]
internal static class Patch_Character_Awake
{
[HarmonyPostfix]
private static void Postfix(Character __instance)
{
if ((Object)(object)((Component)__instance).GetComponent<BleedingTracker>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<BleedingTracker>();
}
}
}
[HarmonyPatch(typeof(Character), "CanRegenStamina")]
internal static class Patch_CanRegenStamina
{
[HarmonyPostfix]
private static void Postfix(Character __instance, ref bool __result)
{
if (__instance.IsLocal)
{
BleedingTracker component = ((Component)__instance).GetComponent<BleedingTracker>();
if ((Object)(object)component != (Object)null && component.isBleeding)
{
__result = false;
}
}
}
}
[HarmonyPatch(typeof(Action_ClearAllStatus), "RunAction")]
internal static class Patch_ClearAllStatus
{
private static readonly FieldInfo _itemField = AccessTools.Field(typeof(Action_ClearAllStatus), "item");
[HarmonyPostfix]
private static void Postfix(Action_ClearAllStatus __instance)
{
try
{
object? obj = _itemField?.GetValue(__instance);
object? obj2 = ((obj is Item) ? obj : null);
Character val = ((obj2 != null) ? ((Item)obj2).holderCharacter : null);
if (!((Object)(object)val == (Object)null) && val.IsLocal)
{
((Component)val).GetComponent<BleedingTracker>()?.CureBleeding();
}
}
catch (Exception ex)
{
BleedingPlugin.Logger.LogWarning((object)("[Bleeding] ClearAllStatus: " + ex.Message));
}
}
}
internal static class SpiderCheck
{
private const float WEB_THRESHOLD = 0.025f;
public static bool IsGrabbedBySpider(Character c)
{
if ((Object)(object)c == (Object)null || c.refs == null || (Object)(object)c.refs.afflictions == (Object)null)
{
return false;
}
try
{
return c.refs.afflictions.GetCurrentStatus((STATUSTYPE)11) > 0.025f;
}
catch
{
return false;
}
}
}
public class TambiAfflictionOption : CustomOptionBase
{
private static readonly Dictionary<string, int> _values = new Dictionary<string, int>();
public string modName;
public string[] labels = new string[4] { "OFF", "LOW", "NORM", "HIGH" };
public int defaultValue = 2;
public Button button;
public LocalizedText buttonText;
public LocalizedText label;
public Image buttonImage;
public Color offColor;
public Color defaultColor;
public Color adjustedColor;
public static int GetValue(string mod)
{
if (!_values.TryGetValue(mod, out var value))
{
return 2;
}
return value;
}
public static void SetValue(string mod, int value)
{
_values[mod] = value;
}
private void OnEnable()
{
if (!_values.ContainsKey(modName))
{
_values[modName] = defaultValue;
}
Refresh();
}
public override void OnClick()
{
((CustomOptionBase)this).OnClick();
int value = GetValue(modName);
value = (value + 1) % labels.Length;
_values[modName] = value;
Refresh();
}
public override void RestoreDefault()
{
_values[modName] = defaultValue;
Refresh();
}
private void Refresh()
{
//IL_006f: 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)
int value = GetValue(modName);
if ((Object)(object)buttonText != (Object)null)
{
buttonText.autoSet = true;
buttonText.SetIndex(labels[Mathf.Clamp(value, 0, labels.Length - 1)]);
}
if ((Object)(object)buttonImage != (Object)null)
{
((Graphic)buttonImage).color = ((value == defaultValue) ? defaultColor : adjustedColor);
}
if ((Object)(object)label != (Object)null)
{
label.SetText(modName);
}
}
}
[HarmonyPatch(typeof(CustomOptionsWindow), "Initialize")]
internal static class TambiOptionInjector
{
private const string MOD_NAME = "Bleeding";
private static bool _injected;
[HarmonyPostfix]
private static void Postfix(CustomOptionsWindow __instance)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Invalid comparison between Unknown and I4
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Invalid comparison between Unknown and I4
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: 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_017c: 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_0185: 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_01c9: Unknown result type (might be due to invalid IL or missing references)
//IL_01d3: Expected O, but got Unknown
if (_injected)
{
return;
}
try
{
CustomOptionMulti[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<CustomOptionMulti>(true);
CustomOptionMulti val = null;
CustomOptionMulti[] array = componentsInChildren;
foreach (CustomOptionMulti val2 in array)
{
if ((int)val2.settingType == 300 || (int)val2.settingType == 400)
{
val = val2;
break;
}
}
if ((Object)(object)val == (Object)null)
{
return;
}
GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
((Object)val3).name = "TambiOption_Bleeding";
CustomOptionMulti component = val3.GetComponent<CustomOptionMulti>();
if ((Object)(object)component == (Object)null)
{
Object.Destroy((Object)(object)val3);
return;
}
Button button = component.button;
LocalizedText buttonText = component.buttonText;
LocalizedText label = component.label;
Image buttonImage = component.buttonImage;
Color offColor = component.offColor;
Color defaultColor = component.defaultColor;
Color adjustedColor = component.adjustedColor;
string[] labels = component.labels;
MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren<MonoBehaviour>(true);
foreach (MonoBehaviour val4 in componentsInChildren2)
{
if (!((Object)(object)val4 == (Object)null))
{
if (val4 is EventTrigger)
{
Object.DestroyImmediate((Object)(object)val4);
}
else if (val4 is CustomOptionBase)
{
Object.DestroyImmediate((Object)(object)val4);
}
else if (val4 is CustomOptionTooltip)
{
Object.DestroyImmediate((Object)(object)val4);
}
}
}
TambiAfflictionOption tambiAfflictionOption = val3.AddComponent<TambiAfflictionOption>();
tambiAfflictionOption.modName = "Bleeding";
tambiAfflictionOption.button = button;
tambiAfflictionOption.buttonText = buttonText;
tambiAfflictionOption.label = label;
tambiAfflictionOption.buttonImage = buttonImage;
tambiAfflictionOption.offColor = offColor;
tambiAfflictionOption.defaultColor = defaultColor;
tambiAfflictionOption.adjustedColor = adjustedColor;
tambiAfflictionOption.defaultValue = 2;
if (labels != null && labels.Length != 0)
{
tambiAfflictionOption.labels = labels;
}
if ((Object)(object)button != (Object)null)
{
((UnityEventBase)button.onClick).RemoveAllListeners();
((UnityEvent)button.onClick).AddListener(new UnityAction(((CustomOptionBase)tambiAfflictionOption).OnClick));
}
if ((Object)(object)label != (Object)null)
{
label.autoSet = false;
label.index = "";
label.SetText("Bleeding");
}
val3.SetActive(true);
((Component)tambiAfflictionOption).SendMessage("Refresh", (SendMessageOptions)1);
_injected = true;
ManualLogSource logger = BleedingPlugin.Logger;
if (logger != null)
{
logger.LogInfo((object)"[TambiOption] Bleeding option injected into Custom Expedition menu.");
}
}
catch (Exception ex)
{
ManualLogSource logger2 = BleedingPlugin.Logger;
if (logger2 != null)
{
logger2.LogWarning((object)("[TambiOption] Injection failed: " + ex.Message));
}
}
}
}
}