using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PerfectRandom.Sulfur.Core;
using PerfectRandom.Sulfur.Core.UI;
using PerfectRandom.Sulfur.Core.Units;
using PerfectRandom.Sulfur.Gameplay;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Enemy Health Bars")]
[assembly: AssemblyProduct("Enemy Health Bars")]
[assembly: AssemblyCompany("Ryuka")]
[assembly: ComVisible(false)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.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 EnemyHealthBars
{
internal static class BarArt
{
public const float PixelsPerCanvasUnit = 4f;
public const int RoundsCount = 10;
public const float SulfurFillStart = 0.018656716f;
public const float SulfurFillEnd = 0.98134327f;
public const float RoundsFillStart = 3f / 134f;
public const float RoundsFillEnd = 131f / 134f;
public const float IchorFillStart = 0.045774646f;
public const float IchorFillEnd = 0.95422536f;
public const float BoneFillStart = 15f / 136f;
public const float BoneFillEnd = 0.9669118f;
public const float ClassicFillStart = 1f / 122f;
public const float ClassicFillEnd = 121f / 122f;
public const float SulfurMarkLeft = 90f;
public const float SulfurMarkTop = 8f;
public const float SulfurMarkPivotX = 122f;
public const float SulfurMarkPivotY = 14f;
public const float SulfurSkullX = 120.86f;
public const float SulfurSkullY = 35.995f;
public const float SulfurSkullHeight = 9.75f;
public const float SulfurSkullAngle = -4f;
public const bool SulfurMarkBehind = false;
public const float RoundsMarkLeft = 137f;
public const float RoundsMarkTop = -7f;
public const float RoundsMarkPivotX = 134f;
public const float RoundsMarkPivotY = 12.5f;
public const float RoundsSkullX = 145.5f;
public const float RoundsSkullY = 16.4f;
public const float RoundsSkullHeight = 6f;
public const float RoundsSkullAngle = 0f;
public const bool RoundsMarkBehind = false;
public const float IchorMarkLeft = 98f;
public const float IchorMarkTop = 10f;
public const float IchorMarkPivotX = 124f;
public const float IchorMarkPivotY = 12f;
public const float IchorSkullX = 128.2f;
public const float IchorSkullY = 59.25f;
public const float IchorSkullHeight = 19.5f;
public const float IchorSkullAngle = 0f;
public const bool IchorMarkBehind = true;
public const float BoneMarkLeft = -17.5f;
public const float BoneMarkTop = -14f;
public const float BoneMarkPivotX = 7.5f;
public const float BoneMarkPivotY = 11f;
public const float BoneSkullX = 0f;
public const float BoneSkullY = 0f;
public const float BoneSkullHeight = 0f;
public const float BoneSkullAngle = 0f;
public const bool BoneMarkBehind = true;
public const float ClassicMarkLeft = 124f;
public const float ClassicMarkTop = -5.5f;
public const float ClassicMarkPivotX = 122f;
public const float ClassicMarkPivotY = 5.5f;
public const float ClassicSkullX = 135f;
public const float ClassicSkullY = 5.5f;
public const float ClassicSkullHeight = 13.6f;
public const float ClassicSkullAngle = 0f;
public const bool ClassicMarkBehind = false;
}
public enum BarStyleId
{
Sulfur = 1,
Rounds,
Ichor,
Bone,
Classic
}
internal sealed class BarStyle
{
private struct MarkLayout
{
public float Left;
public float Top;
public float PivotX;
public float PivotY;
public float SkullX;
public float SkullY;
public float SkullHeight;
public float SkullAngle;
public bool Behind;
public bool HasEyes;
public Color SkullBone;
public Color SkullHoles;
}
private static readonly Color HudRed = new Color(35f / 51f, 0.2980392f, 0.290196f, 1f);
private static readonly Color PaleTrail = new Color(0.96f, 0.85f, 0.66f, 0.9f);
private static readonly Color SkullColor = new Color(0.94f, 0.91f, 0.63f, 1f);
private static readonly Dictionary<BarStyleId, BarStyle> Loaded = new Dictionary<BarStyleId, BarStyle>();
private static readonly List<Object> Owned = new List<Object>();
private static MethodInfo _decodeImage;
private bool _marksTried;
private static readonly Color SkullDark = new Color(0.11372549f, 0.23137255f, 0.2f, 1f);
private static readonly Color SeeThrough = new Color(0f, 0f, 0f, 0f);
private static readonly Dictionary<BarStyleId, MarkLayout> Layouts = new Dictionary<BarStyleId, MarkLayout>
{
{
BarStyleId.Sulfur,
new MarkLayout
{
Left = 90f,
Top = 8f,
PivotX = 122f,
PivotY = 14f,
SkullX = 120.86f,
SkullY = 35.995f,
SkullHeight = 9.75f,
SkullAngle = -4f,
Behind = false,
SkullBone = SkullDark,
SkullHoles = SeeThrough
}
},
{
BarStyleId.Rounds,
new MarkLayout
{
Left = 137f,
Top = -7f,
PivotX = 134f,
PivotY = 12.5f,
SkullX = 145.5f,
SkullY = 16.4f,
SkullHeight = 6f,
SkullAngle = 0f,
Behind = false,
SkullBone = SkullDark,
SkullHoles = SeeThrough
}
},
{
BarStyleId.Ichor,
new MarkLayout
{
Left = 98f,
Top = 10f,
PivotX = 124f,
PivotY = 12f,
SkullX = 128.2f,
SkullY = 59.25f,
SkullHeight = 19.5f,
SkullAngle = 0f,
Behind = true,
SkullBone = SulfurConstants.COLOR_SulfurYellow,
SkullHoles = SkullDark
}
},
{
BarStyleId.Bone,
new MarkLayout
{
Left = -17.5f,
Top = -14f,
PivotX = 7.5f,
PivotY = 11f,
SkullX = 0f,
SkullY = 0f,
SkullHeight = 0f,
SkullAngle = 0f,
Behind = true,
HasEyes = true,
SkullBone = SkullDark,
SkullHoles = SeeThrough
}
},
{
BarStyleId.Classic,
new MarkLayout
{
Left = 124f,
Top = -5.5f,
PivotX = 122f,
PivotY = 5.5f,
SkullX = 135f,
SkullY = 5.5f,
SkullHeight = 13.6f,
SkullAngle = 0f,
Behind = false,
SkullBone = SkullDark,
SkullHoles = SeeThrough
}
}
};
public BarStyleId Id { get; private set; }
public Vector2 Size { get; private set; }
public float FillStart { get; private set; }
public float FillEnd { get; private set; }
public int Steps { get; private set; }
public bool FollowsUiColor { get; private set; }
public Color FillColor { get; private set; }
public Color TrailColor { get; private set; }
public Color NameColor { get; private set; }
public Sprite Back { get; private set; }
public Sprite Fill { get; private set; }
public Sprite Frame { get; private set; }
public Sprite[] Marks { get; private set; }
public Sprite MarkEyes { get; private set; }
public Rect MarkRect { get; private set; }
public Vector2 MarkPivot { get; private set; }
public bool MarkBehind { get; private set; }
public Vector2 SkullCentre { get; private set; }
public float SkullHeight { get; private set; }
public float SkullAngle { get; private set; }
public Color SkullBoneColor { get; private set; }
public Color SkullHoleColor { get; private set; }
public float FillAmount(float health)
{
if (health <= 0f)
{
return 0f;
}
float num = Mathf.Clamp01(health);
if (Steps > 0)
{
num = Mathf.Ceil(num * (float)Steps) / (float)Steps;
}
return Mathf.Lerp(FillStart, FillEnd, num);
}
public static BarStyle Get(BarStyleId id)
{
if (Loaded.TryGetValue(id, out var value))
{
return value;
}
value = Load(id);
if (value == null && id != BarStyleId.Classic)
{
value = Get(BarStyleId.Classic);
}
Loaded[id] = value;
return value;
}
public static void Unload()
{
foreach (Object item in Owned)
{
Object.Destroy(item);
}
Owned.Clear();
Loaded.Clear();
}
private static BarStyle Load(BarStyleId id)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: 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_0086: Unknown result type (might be due to invalid IL or missing references)
BarStyle barStyle = Describe(id);
if (barStyle == null)
{
Plugin.Log.LogError((object)("Unknown bar style " + id.ToString() + "."));
return null;
}
try
{
barStyle.Id = id;
barStyle.Back = LoadSprite(id, "back");
barStyle.Fill = LoadSprite(id, "fill");
barStyle.Frame = LoadSprite(id, "frame");
Rect rect = barStyle.Back.rect;
barStyle.Size = ((Rect)(ref rect)).size / 4f;
return barStyle;
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Bar style " + id.ToString() + " could not be loaded: " + ex.Message));
return null;
}
}
public bool EnsureMarks()
{
if (_marksTried)
{
return false;
}
_marksTried = true;
LoadMarks(this);
return Marks != null;
}
private static void LoadMarks(BarStyle style)
{
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: 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_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_00ad: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: 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)
if (!Layouts.TryGetValue(style.Id, out var value))
{
return;
}
try
{
Sprite[] array = (Sprite[])(object)new Sprite[3];
for (int i = 0; i < array.Length; i++)
{
array[i] = LoadSprite(style.Id, "mark" + (i + 1));
}
style.MarkEyes = (value.HasEyes ? LoadSprite(style.Id, "eyes") : null);
float y = style.Size.y;
Rect rect = array[0].rect;
Vector2 val = ((Rect)(ref rect)).size / 4f;
style.MarkRect = new Rect(value.Left, y - value.Top - val.y, val.x, val.y);
style.MarkPivot = new Vector2(value.PivotX, y - value.PivotY);
style.SkullCentre = new Vector2(value.SkullX, y - value.SkullY);
style.SkullHeight = value.SkullHeight;
style.SkullAngle = value.SkullAngle;
style.MarkBehind = value.Behind;
style.SkullBoneColor = value.SkullBone;
style.SkullHoleColor = value.SkullHoles;
style.Marks = array;
}
catch (Exception ex)
{
style.Marks = null;
style.MarkEyes = null;
Plugin.Log.LogError((object)("Team marks for bar style " + style.Id.ToString() + " could not be loaded: " + ex.Message));
}
}
private static bool DecodeImage(Texture2D texture, byte[] bytes)
{
if (_decodeImage == null)
{
_decodeImage = AccessTools.TypeByName("UnityEngine.ImageConversion")?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
{
typeof(Texture2D),
typeof(byte[]),
typeof(bool)
}, null);
if (_decodeImage == null)
{
throw new MissingMethodException("UnityEngine.ImageConversion", "LoadImage");
}
}
return (bool)_decodeImage.Invoke(null, new object[3] { texture, bytes, true });
}
private static BarStyle Describe(BarStyleId id)
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: 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_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
return id switch
{
BarStyleId.Sulfur => new BarStyle
{
FillStart = 0.018656716f,
FillEnd = 0.98134327f,
FollowsUiColor = true,
FillColor = HudRed,
TrailColor = PaleTrail,
NameColor = Color.white
},
BarStyleId.Rounds => new BarStyle
{
FillStart = 3f / 134f,
FillEnd = 131f / 134f,
Steps = 10,
FollowsUiColor = true,
FillColor = HudRed,
TrailColor = PaleTrail,
NameColor = Color.white
},
BarStyleId.Ichor => new BarStyle
{
FillStart = 0.045774646f,
FillEnd = 0.95422536f,
FillColor = HudRed,
TrailColor = PaleTrail,
NameColor = Color.white
},
BarStyleId.Bone => new BarStyle
{
FillStart = 15f / 136f,
FillEnd = 0.9669118f,
FillColor = HudRed,
TrailColor = PaleTrail,
NameColor = SkullColor
},
BarStyleId.Classic => new BarStyle
{
FillStart = 1f / 122f,
FillEnd = 121f / 122f,
FillColor = new Color(0.82f, 0.16f, 0.13f, 1f),
TrailColor = new Color(0.95f, 0.85f, 0.75f, 0.9f),
NameColor = Color.white
},
_ => null,
};
}
private static Sprite LoadSprite(BarStyleId id, string layer)
{
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Expected O, but got Unknown
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
string text = "EnemyHealthBars.Styles." + id.ToString() + "." + layer + ".png";
byte[] array;
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text))
{
if (stream == null)
{
throw new FileNotFoundException("missing resource", text);
}
array = new byte[stream.Length];
int num;
for (int i = 0; i < array.Length; i += num)
{
num = stream.Read(array, i, array.Length - i);
if (num <= 0)
{
throw new EndOfStreamException(text);
}
}
}
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true)
{
name = text,
wrapMode = (TextureWrapMode)1,
filterMode = (FilterMode)2
};
((Object)val).hideFlags = (HideFlags)61;
Owned.Add((Object)(object)val);
if (!DecodeImage(val, array))
{
throw new InvalidDataException("not an image: " + text);
}
Rect val2 = default(Rect);
((Rect)(ref val2))..ctor(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height);
Sprite val3 = Sprite.Create(val, val2, new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
((Object)val3).name = text;
((Object)val3).hideFlags = (HideFlags)61;
Owned.Add((Object)(object)val3);
return val3;
}
}
[HarmonyPatch(typeof(BossHealth))]
internal static class BossBarTracker
{
private static readonly Dictionary<BossHealth, Unit> Attached = new Dictionary<BossHealth, Unit>();
public static bool Shows(Unit unit)
{
foreach (KeyValuePair<BossHealth, Unit> item in Attached)
{
if ((Object)(object)item.Value == (Object)(object)unit)
{
return true;
}
}
return false;
}
public static void Reset()
{
Attached.Clear();
}
[HarmonyPostfix]
[HarmonyPatch("Attach")]
private static void AfterAttach(BossHealth __instance, Unit unit)
{
Attached[__instance] = unit;
}
[HarmonyPostfix]
[HarmonyPatch("Detach")]
private static void AfterDetach(BossHealth __instance, Unit unit)
{
if (Attached.TryGetValue(__instance, out var value) && ((Object)(object)unit == (Object)null || (Object)(object)unit == (Object)(object)value))
{
Attached.Remove(__instance);
}
}
}
internal static class EnemyRules
{
private static readonly FieldRef<Npc, float> CurrentOpacity = ResolveOpacity("unitOpacity");
private static readonly FieldRef<Npc, float> TargetOpacity = ResolveOpacity("unitTargetOpacity");
private const float HiddenBelowOpacity = 0.5f;
private static FieldRef<Npc, float> ResolveOpacity(string field)
{
try
{
return AccessTools.FieldRefAccess<Npc, float>(field);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Npc." + field + " was not found; ghosts will never show a bar: " + ex.Message));
return null;
}
}
public static bool CanEverShow(Npc npc)
{
if ((Object)(object)((Unit)npc).unitSO != (Object)null && ((Unit)npc).Stats != null && !((Unit)npc).IsProtectedNpc && !((Unit)npc).IsCivilian)
{
return !((Unit)npc).IsBoss;
}
return false;
}
public static bool CanShowNow(TrackedEnemy enemy, Unit player)
{
Npc npc = enemy.Npc;
if (!((Component)npc).gameObject.activeInHierarchy || !((Unit)npc).IsAlive || ((Unit)npc).GetCurrentHealth() <= 0f)
{
return false;
}
if (!((Unit)npc).IsHostileTo(player))
{
return false;
}
if (((Unit)npc).IsCharmed || (Object)(object)npc.forcedCharmingOwner != (Object)null || npc.isFoulAlly)
{
return false;
}
if (!IsHidden(enemy) && (Object)(object)((Unit)npc).unitFrame == (Object)null)
{
return !BossBarTracker.Shows((Unit)(object)npc);
}
return false;
}
private static bool IsHidden(TrackedEnemy enemy)
{
Npc npc = enemy.Npc;
if (((Unit)npc).isInvisible || npc.HiddenMode || !((Unit)npc).Targetable)
{
return true;
}
if ((Object)(object)enemy.Sniper != (Object)null && enemy.Sniper.IsHidden)
{
return true;
}
if ((Object)(object)npc.mainRenderer != (Object)null && !((Component)npc.mainRenderer).gameObject.activeInHierarchy)
{
return true;
}
if (CurrentOpacity == null || TargetOpacity == null)
{
return enemy.IsGhost;
}
if (!(CurrentOpacity.Invoke(npc) < 0.5f))
{
return TargetOpacity.Invoke(npc) < 0.5f;
}
return true;
}
}
public static class HealthBarIntegration
{
public const int MaxMarks = 3;
private static Func<object, int> _markCount;
private static bool _marksChanged;
internal static bool HasMarkSource => _markCount != null;
public static void SetMarkSource(Func<object, int> markCount)
{
_markCount = markCount;
_marksChanged = true;
}
public static void NotifyMarksChanged()
{
_marksChanged = true;
}
public static bool IsShowingMarks(object unit)
{
return HealthBarManager.IsShowingMarks(unit);
}
internal static bool TakeMarksChanged()
{
bool marksChanged = _marksChanged;
_marksChanged = false;
return marksChanged;
}
internal static int ReadMarks(object unit)
{
Func<object, int> markCount = _markCount;
if (markCount == null)
{
return 0;
}
try
{
int num = markCount(unit);
return (num >= 0) ? ((num > 3) ? 3 : num) : 0;
}
catch (Exception ex)
{
if ((object)_markCount == markCount)
{
_markCount = null;
_marksChanged = true;
Plugin.Log.LogError((object)("Team marks are off for this session: reading them failed. " + ex));
}
return 0;
}
}
}
internal sealed class HealthBarManager : MonoBehaviour
{
private const string BattleImprovementsGuid = "BattleImprove";
private const int MaxBars = 32;
private const float ScanInterval = 0.1f;
private const float SightInterval = 0.15f;
private const float ShowSeconds = 6f;
private const float FadeSeconds = 0.75f;
private const float AlphaPerSecond = 8f;
private const float TrailDelayPerSecond = 0.6f;
private const float HealthEpsilon = 0.0005f;
private const float ScreenMargin = 0.03f;
private const float BarHeightOnScreen = 0.05f;
private const float MinDistanceScale = 0.65f;
private const float StealMargin = 3f;
private const float FontRetrySeconds = 1f;
private const float ErrorLogSeconds = 10f;
private const float MarkReadInterval = 0.5f;
private const float MarkVisibleAlpha = 0.5f;
private static HealthBarManager _instance;
private readonly Dictionary<int, TrackedEnemy> _byId = new Dictionary<int, TrackedEnemy>();
private readonly List<TrackedEnemy> _tracked = new List<TrackedEnemy>();
private readonly Stack<HealthBarView> _freeViews = new Stack<HealthBarView>();
private Canvas _canvas;
private RectTransform _canvasRect;
private int _viewsCreated;
private int _scan;
private float _nextScanTime;
private TMP_FontAsset _font;
private BarStyle _style;
private Color _uiColor;
private bool _languageDirty = true;
private float _nextFontAttempt;
private AsyncAssetLoading _languageSource;
private float _nextErrorLog;
private bool _overlapChecked;
private int _shownFrame = int.MinValue;
private bool _marksOn;
private float _nextMarkRead;
private Sprite _skull;
public static void EnsureExists()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("Enemy Health Bars");
Object.DontDestroyOnLoad((Object)val);
_instance = val.AddComponent<HealthBarManager>();
}
}
public static void Shutdown()
{
if (!((Object)(object)_instance == (Object)null))
{
HealthBarManager instance = _instance;
_instance = null;
Object.Destroy((Object)(object)((Component)instance).gameObject);
}
}
private void Awake()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_0086: 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_00ab: Expected O, but got Unknown
GameObject val = new GameObject("Enemy Health Bars Canvas", new Type[2]
{
typeof(Canvas),
typeof(CanvasScaler)
});
val.transform.SetParent(((Component)this).transform, false);
_canvas = val.GetComponent<Canvas>();
_canvas.renderMode = (RenderMode)0;
_canvas.sortingOrder = -100;
((Behaviour)_canvas).enabled = false;
CanvasScaler component = val.GetComponent<CanvasScaler>();
component.uiScaleMode = (ScaleMode)1;
component.referenceResolution = new Vector2(1920f, 1080f);
component.matchWidthOrHeight = 1f;
_canvasRect = (RectTransform)val.transform;
}
private void OnDestroy()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
if ((Object)(object)_languageSource != (Object)null)
{
_languageSource.onLanguageChange = (OnLanguageChange)Delegate.Remove((Delegate?)(object)_languageSource.onLanguageChange, (Delegate?)new OnLanguageChange(OnLanguageChange));
}
}
private void LateUpdate()
{
try
{
Tick();
_shownFrame = (((Behaviour)_canvas).enabled ? Time.frameCount : int.MinValue);
}
catch (Exception ex)
{
((Behaviour)_canvas).enabled = false;
_shownFrame = int.MinValue;
if (Time.unscaledTime >= _nextErrorLog)
{
_nextErrorLog = Time.unscaledTime + 10f;
Plugin.Log.LogError((object)("Health bar update failed: " + ex));
}
}
}
private void Tick()
{
WarnAboutOverlapOnce();
FollowLanguageChanges();
GameManager instance = StaticInstance<GameManager>.Instance;
if (!TryGetLiveView(instance, out var player, out var camera))
{
((Behaviour)_canvas).enabled = false;
return;
}
((Behaviour)_canvas).enabled = true;
if (_languageDirty || (Object)(object)_font == (Object)null)
{
RefreshFont();
}
RefreshStyle();
if (_style != null)
{
float time = Time.time;
if (time >= _nextScanTime)
{
_nextScanTime = time + 0.1f;
Scan(instance.aliveNpcs, time);
}
RefreshMarks(time);
UpdateBars(instance, player, camera, time);
}
}
private void RefreshMarks(float now)
{
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
if (!HealthBarIntegration.HasMarkSource)
{
if (_marksOn)
{
_marksOn = false;
for (int i = 0; i < _tracked.Count; i++)
{
_tracked[i].Marks = 0;
}
}
return;
}
_marksOn = true;
if (_style != null && _style.EnsureMarks())
{
foreach (HealthBarView freeView in _freeViews)
{
freeView.SetStyle(_style, _uiColor);
}
for (int j = 0; j < _tracked.Count; j++)
{
_tracked[j].View?.SetStyle(_style, _uiColor);
}
}
try
{
SkullArt.Tick();
}
catch (Exception e)
{
SkullArt.GiveUp(e);
}
if ((Object)(object)SkullArt.Bone != (Object)(object)_skull)
{
_skull = SkullArt.Bone;
foreach (HealthBarView freeView2 in _freeViews)
{
freeView2.SetSkull(SkullArt.Bone, SkullArt.Holes, SkullArt.Aspect);
}
for (int k = 0; k < _tracked.Count; k++)
{
_tracked[k].View?.SetSkull(SkullArt.Bone, SkullArt.Holes, SkullArt.Aspect);
}
}
if (!HealthBarIntegration.TakeMarksChanged() && now < _nextMarkRead)
{
return;
}
_nextMarkRead = now + 0.5f;
for (int l = 0; l < _tracked.Count; l++)
{
TrackedEnemy trackedEnemy = _tracked[l];
if (trackedEnemy.View != null && (Object)(object)trackedEnemy.Npc != (Object)null)
{
trackedEnemy.Marks = HealthBarIntegration.ReadMarks(trackedEnemy.Npc);
}
}
}
internal static bool IsShowingMarks(object unit)
{
HealthBarManager instance = _instance;
Object val = (Object)((unit is Object) ? unit : null);
if ((Object)(object)instance == (Object)null || val == (Object)null)
{
return false;
}
int num = Time.frameCount - 1;
if (instance._shownFrame >= num && instance._byId.TryGetValue(val.GetInstanceID(), out var value))
{
return value.MarkDrawnFrame == instance._shownFrame;
}
return false;
}
private static bool TryGetLiveView(GameManager game, out Unit player, out Camera camera)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Invalid comparison between Unknown and I4
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Invalid comparison between Unknown and I4
player = null;
camera = null;
if ((Object)(object)game == (Object)null || (int)game.gameState != 3 || game.awaitingStartLevel)
{
return false;
}
if (game.PlayerControllerLocked)
{
return false;
}
Player playerScript = game.PlayerScript;
player = game.PlayerUnit;
if ((Object)(object)playerScript == (Object)null || (Object)(object)player == (Object)null || (int)player.UnitState != 2)
{
return false;
}
if (playerScript.HudHiddenBy((LockStatePadlock)3) || playerScript.HudHiddenBy((LockStatePadlock)6))
{
return false;
}
camera = game.currentCamera;
if ((Object)(object)camera != (Object)null && (Object)(object)camera == (Object)(object)playerScript.playerCamera)
{
return ((Behaviour)camera).isActiveAndEnabled;
}
return false;
}
private void RefreshStyle()
{
//IL_002b: 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_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
BarStyle barStyle = BarStyle.Get(Plugin.Style.Value);
if (barStyle == null)
{
return;
}
UIManager instance = StaticInstance<UIManager>.Instance;
Color val = (((Object)(object)instance != (Object)null) ? instance.CurrentUiColor : SulfurConstants.COLOR_SulfurYellow);
if (barStyle == _style && val == _uiColor)
{
return;
}
_style = barStyle;
_uiColor = val;
foreach (HealthBarView freeView in _freeViews)
{
freeView.SetStyle(barStyle, val);
}
for (int i = 0; i < _tracked.Count; i++)
{
_tracked[i].View?.SetStyle(barStyle, val);
}
}
private void Scan(List<Npc> npcs, float now)
{
_scan++;
for (int i = 0; i < npcs.Count; i++)
{
Npc val = npcs[i];
if ((Object)(object)val == (Object)null)
{
continue;
}
if (!_byId.TryGetValue(((Object)val).GetInstanceID(), out var value))
{
if (!EnemyRules.CanEverShow(val))
{
continue;
}
value = new TrackedEnemy(val);
_byId.Add(value.Id, value);
_tracked.Add(value);
}
value.SeenInScan = _scan;
float normalizedHealth = ((Unit)val).normalizedHealth;
if (float.IsNaN(normalizedHealth))
{
continue;
}
if (normalizedHealth < value.LastHealth - 0.0005f)
{
value.LastHurtTime = now;
if (Plugin.DebugLog.Value)
{
Plugin.Log.LogInfo((object)("[Bars] hurt " + ((Object)val).name + " " + value.LastHealth + " -> " + normalizedHealth));
}
value.LastHealth = normalizedHealth;
}
else if (normalizedHealth > value.LastHealth)
{
value.LastHealth = normalizedHealth;
}
}
for (int num = _tracked.Count - 1; num >= 0; num--)
{
TrackedEnemy trackedEnemy = _tracked[num];
if (trackedEnemy.SeenInScan != _scan || !((Object)(object)trackedEnemy.Npc != (Object)null))
{
ReleaseView(trackedEnemy);
_byId.Remove(trackedEnemy.Id);
_tracked[num] = _tracked[_tracked.Count - 1];
_tracked.RemoveAt(_tracked.Count - 1);
}
}
}
private void UpdateBars(GameManager game, Unit player, Camera camera, float now)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: 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_00d6: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: 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_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
//IL_0269: Unknown result type (might be due to invalid IL or missing references)
//IL_0276: Unknown result type (might be due to invalid IL or missing references)
//IL_027b: Unknown result type (might be due to invalid IL or missing references)
//IL_0285: Unknown result type (might be due to invalid IL or missing references)
//IL_0292: Unknown result type (might be due to invalid IL or missing references)
//IL_0297: Unknown result type (might be due to invalid IL or missing references)
//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
Vector3 position = ((Component)camera).transform.position;
float num = Mathf.Clamp(Plugin.MaxDistance.Value, 5f, 100f);
float num2 = Mathf.Clamp(Plugin.BarScale.Value, 0.5f, 2f);
bool value = Plugin.ShowName.Value;
bool flag = Plugin.Mode.Value == BarDisplayMode.Nearby;
int mask = LayerMask.op_Implicit(game.enemyOcclusionLayers);
TrackedEnemy trackedEnemy = null;
Vector2 position2 = default(Vector2);
for (int i = 0; i < _tracked.Count; i++)
{
TrackedEnemy trackedEnemy2 = _tracked[i];
if ((Object)(object)trackedEnemy2.Npc == (Object)null)
{
ReleaseView(trackedEnemy2);
continue;
}
float num3 = (flag ? 1f : DamagedAlpha(now - trackedEnemy2.LastHurtTime));
if (num3 <= 0f)
{
ReleaseView(trackedEnemy2);
continue;
}
Vector3 val = trackedEnemy2.Anchor();
float num4 = (trackedEnemy2.Distance = Vector3.Distance(position, val));
if (num4 > num || !EnemyRules.CanShowNow(trackedEnemy2, player))
{
ReleaseView(trackedEnemy2);
continue;
}
Vector3 viewport = camera.WorldToViewportPoint(val);
KeepBarOnScreen(ref viewport, camera, trackedEnemy2, num2);
if (viewport.z <= 0f || !IsOnScreen(viewport))
{
ReleaseView(trackedEnemy2);
continue;
}
if (now >= trackedEnemy2.NextSightCheck)
{
trackedEnemy2.NextSightCheck = now + 0.15f + (float)(trackedEnemy2.Id & 7) * 0.01f;
trackedEnemy2.InSight = HasLineOfSight(position, trackedEnemy2, val, mask);
}
float num5 = (trackedEnemy2.InSight ? num3 : 0f);
trackedEnemy2.Alpha = Mathf.MoveTowards(trackedEnemy2.Alpha, num5, 8f * Time.deltaTime);
if (trackedEnemy2.Alpha <= 0f && num5 <= 0f)
{
ReleaseView(trackedEnemy2);
continue;
}
if (trackedEnemy2.View == null && !TryAcquireView(trackedEnemy2))
{
if (trackedEnemy == null || num4 < trackedEnemy.Distance)
{
trackedEnemy = trackedEnemy2;
}
continue;
}
float normalizedHealth = ((Unit)trackedEnemy2.Npc).normalizedHealth;
normalizedHealth = (float.IsNaN(normalizedHealth) ? 0f : Mathf.Clamp01(normalizedHealth));
trackedEnemy2.Trail = Mathf.Max(normalizedHealth, Mathf.MoveTowards(trackedEnemy2.Trail, normalizedHealth, 0.6f * Time.deltaTime));
float num6 = Mathf.Lerp(1f, 0.65f, num4 / num);
float x = viewport.x;
Rect rect = _canvasRect.rect;
float num7 = x * ((Rect)(ref rect)).width;
float y = viewport.y;
rect = _canvasRect.rect;
((Vector2)(ref position2))..ctor(num7, y * ((Rect)(ref rect)).height);
string name = null;
if (value)
{
if (trackedEnemy2.Name == null)
{
trackedEnemy2.Name = ((Unit)trackedEnemy2.Npc).unitSO.LocalizedIdentifier();
}
name = trackedEnemy2.Name;
}
if (trackedEnemy2.View.Show(position2, num2 * num6, trackedEnemy2.Alpha, normalizedHealth, trackedEnemy2.Trail, name, trackedEnemy2.Marks) && trackedEnemy2.Alpha >= 0.5f)
{
trackedEnemy2.MarkDrawnFrame = Time.frameCount;
}
}
if (trackedEnemy != null && TryTakeFromFarther(trackedEnemy.Distance))
{
TryAcquireView(trackedEnemy);
}
}
private static void KeepBarOnScreen(ref Vector3 viewport, Camera camera, TrackedEnemy enemy, float barScale)
{
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
float num = 1f - 0.05f * barScale;
if (!(viewport.z <= 0f) && !(viewport.y <= num) && (viewport.y <= 1.03f || IsInView(camera, ((Unit)enemy.Npc).GetPositionToAimAt()) || IsInView(camera, ((Component)enemy.Npc).transform.position)))
{
viewport.y = num;
}
}
private static bool IsInView(Camera camera, Vector3 world)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = camera.WorldToViewportPoint(world);
if (val.z > 0f)
{
return IsOnScreen(val);
}
return false;
}
private static float DamagedAlpha(float secondsSinceHurt)
{
if (secondsSinceHurt <= 6f)
{
return 1f;
}
return Mathf.Clamp01(1f - (secondsSinceHurt - 6f) / 0.75f);
}
private static bool IsOnScreen(Vector3 viewport)
{
//IL_0000: 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_001a: 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)
if (viewport.x >= -0.03f && viewport.x <= 1.03f && viewport.y >= -0.03f)
{
return viewport.y <= 1.03f;
}
return false;
}
private static bool HasLineOfSight(Vector3 eye, TrackedEnemy enemy, Vector3 anchor, int mask)
{
//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_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: 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_002b: Unknown result type (might be due to invalid IL or missing references)
Vector3 to = anchor - Vector3.up * 0.2f;
if (!IsClear(eye, ((Unit)enemy.Npc).GetPositionToAimAt(), mask))
{
return IsClear(eye, to, mask);
}
return true;
}
private static bool IsClear(Vector3 from, Vector3 to, int mask)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = to - from;
float magnitude = ((Vector3)(ref val)).magnitude;
if (magnitude < 0.01f)
{
return true;
}
return !Physics.Raycast(from, val / magnitude, magnitude, mask, (QueryTriggerInteraction)1);
}
private bool TryAcquireView(TrackedEnemy enemy)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
if (_freeViews.Count == 0 && _viewsCreated < 32)
{
HealthBarView healthBarView = new HealthBarView((Transform)(object)_canvasRect);
healthBarView.SetFont(_font);
healthBarView.SetSkull(SkullArt.Bone, SkullArt.Holes, SkullArt.Aspect);
healthBarView.SetStyle(_style, _uiColor);
_viewsCreated++;
_freeViews.Push(healthBarView);
}
if (_freeViews.Count == 0)
{
return false;
}
enemy.View = _freeViews.Pop();
enemy.Marks = HealthBarIntegration.ReadMarks(enemy.Npc);
if (Plugin.DebugLog.Value)
{
Plugin.Log.LogInfo((object)("[Bars] show " + ((Object)enemy.Npc).name + " at " + enemy.LastHealth));
}
return true;
}
private bool TryTakeFromFarther(float distance)
{
TrackedEnemy trackedEnemy = null;
float num = distance + 3f;
for (int i = 0; i < _tracked.Count; i++)
{
TrackedEnemy trackedEnemy2 = _tracked[i];
if (trackedEnemy2.View != null && !(trackedEnemy2.Distance <= num))
{
trackedEnemy = trackedEnemy2;
num = trackedEnemy2.Distance;
}
}
if (trackedEnemy == null)
{
return false;
}
ReleaseView(trackedEnemy);
return true;
}
private void ReleaseView(TrackedEnemy enemy)
{
enemy.Alpha = 0f;
enemy.MarkDrawnFrame = int.MinValue;
if (enemy.View != null)
{
enemy.View.Hide();
_freeViews.Push(enemy.View);
enemy.View = null;
}
}
private void FollowLanguageChanges()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
if (!((Object)(object)_languageSource != (Object)null))
{
AsyncAssetLoading instance = StaticInstance<AsyncAssetLoading>.Instance;
if (!((Object)(object)instance == (Object)null))
{
_languageSource = instance;
instance.onLanguageChange = (OnLanguageChange)Delegate.Combine((Delegate?)(object)instance.onLanguageChange, (Delegate?)new OnLanguageChange(OnLanguageChange));
}
}
}
private void OnLanguageChange()
{
_languageDirty = true;
}
private void RefreshFont()
{
if (Time.unscaledTime < _nextFontAttempt)
{
return;
}
_nextFontAttempt = Time.unscaledTime + 1f;
AsyncAssetLoading instance = StaticInstance<AsyncAssetLoading>.Instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
int num = 1;
if ((Object)(object)instance.fontCache[num] == (Object)null)
{
FontLocalizer.LoadFontCache();
}
TMP_FontAsset val = instance.fontCache[num];
if ((Object)(object)val == (Object)null)
{
return;
}
_font = val;
_languageDirty = false;
foreach (HealthBarView freeView in _freeViews)
{
freeView.SetFont(val);
}
for (int i = 0; i < _tracked.Count; i++)
{
_tracked[i].Name = null;
_tracked[i].View?.SetFont(val);
}
}
private void WarnAboutOverlapOnce()
{
if (!_overlapChecked)
{
_overlapChecked = true;
if (Chainloader.PluginInfos.ContainsKey("BattleImprove"))
{
Plugin.Log.LogWarning((object)"Battle Improvements is installed and has its own enemy health bar. Turn off EnableHealthBar in its settings to avoid two bars on each enemy.");
}
}
}
}
internal sealed class HealthBarView
{
private const float NameGap = 2f;
private const float NameFontSize = 18f;
private const float NameWidth = 360f;
private static readonly Color NameShadowColor = new Color(0f, 0f, 0f, 0.9f);
private static readonly Vector2 NameShadowOffset = new Vector2(1.5f, -1.5f);
private readonly GameObject _root;
private readonly RectTransform _rootRect;
private readonly CanvasGroup _group;
private readonly Image _back;
private readonly Image _trail;
private readonly Image _fill;
private readonly Image _frame;
private readonly GameObject _nameRoot;
private readonly TextMeshProUGUI _name;
private readonly TextMeshProUGUI _nameShadow;
private const float MinMarkScale = 0.65f;
private const float PopSeconds = 0.2f;
private const float PopAmount = 0.3f;
private readonly RectTransform _markRoot;
private readonly Image _mark;
private readonly Image _skullBone;
private readonly Image _skullHoles;
private readonly Image _eyes;
private Sprite _skullBoneSprite;
private Sprite _skullHolesSprite;
private float _skullAspect = 1f;
private int _shownMarks;
private bool _marksFresh = true;
private float _popStart = float.NegativeInfinity;
private BarStyle _style;
private string _shownName;
public HealthBarView(Transform parent)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Expected O, but got Unknown
//IL_0081: 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_00ab: 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_0156: Expected O, but got Unknown
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Expected O, but got Unknown
//IL_017f: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: 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_0220: Unknown result type (might be due to invalid IL or missing references)
//IL_0256: Unknown result type (might be due to invalid IL or missing references)
//IL_0260: Expected O, but got Unknown
//IL_0282: Unknown result type (might be due to invalid IL or missing references)
//IL_0288: Expected O, but got Unknown
//IL_0293: Unknown result type (might be due to invalid IL or missing references)
//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0313: Unknown result type (might be due to invalid IL or missing references)
//IL_0318: Unknown result type (might be due to invalid IL or missing references)
_root = new GameObject("Enemy Health Bar", new Type[2]
{
typeof(RectTransform),
typeof(CanvasGroup)
});
_root.transform.SetParent(parent, false);
_rootRect = (RectTransform)_root.transform;
_rootRect.anchorMin = Vector2.zero;
_rootRect.anchorMax = Vector2.zero;
_rootRect.pivot = new Vector2(0.5f, 0f);
_group = _root.GetComponent<CanvasGroup>();
_group.interactable = false;
_group.blocksRaycasts = false;
_back = CreateImage("Back", filled: false);
_trail = CreateImage("Trail", filled: true);
_fill = CreateImage("Fill", filled: true);
_frame = CreateImage("Frame", filled: false);
_eyes = CreateImage("Mark Eyes", filled: false);
GameObject val = new GameObject("Mark", new Type[1] { typeof(RectTransform) });
val.transform.SetParent((Transform)(object)_rootRect, false);
_markRoot = (RectTransform)val.transform;
_markRoot.anchorMin = Vector2.zero;
_markRoot.anchorMax = Vector2.zero;
_markRoot.pivot = Vector2.zero;
_markRoot.sizeDelta = Vector2.zero;
_mark = CreateMarkImage("Mark Art");
_skullBone = CreateMarkImage("Skull");
_skullHoles = CreateMarkImage("Skull Holes");
((Graphic)_skullBone).rectTransform.pivot = new Vector2(0.5f, 0.5f);
((Graphic)_skullHoles).rectTransform.pivot = new Vector2(0.5f, 0.5f);
val.SetActive(false);
((Behaviour)_eyes).enabled = false;
_nameRoot = new GameObject("Name", new Type[1] { typeof(RectTransform) });
_nameRoot.transform.SetParent((Transform)(object)_rootRect, false);
RectTransform val2 = (RectTransform)_nameRoot.transform;
val2.anchorMin = new Vector2(0.5f, 1f);
val2.anchorMax = new Vector2(0.5f, 1f);
val2.pivot = new Vector2(0.5f, 0f);
val2.anchoredPosition = new Vector2(0f, 2f);
val2.sizeDelta = new Vector2(360f, 27f);
_nameShadow = CreateText("Shadow", (Transform)(object)val2, NameShadowColor, NameShadowOffset);
_name = CreateText("Text", (Transform)(object)val2, Color.white, Vector2.zero);
Hide();
}
public void SetFont(TMP_FontAsset font)
{
if (!((Object)(object)font == (Object)null))
{
((TMP_Text)_name).font = font;
((TMP_Text)_nameShadow).font = font;
}
}
public void SetStyle(BarStyle style, Color uiColor)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: 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_008c: 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)
_style = style;
_rootRect.sizeDelta = style.Size;
_back.sprite = style.Back;
_trail.sprite = style.Fill;
_fill.sprite = style.Fill;
_frame.sprite = style.Frame;
((Graphic)_trail).color = style.TrailColor;
((Graphic)_fill).color = style.FillColor;
((Graphic)_frame).color = (style.FollowsUiColor ? uiColor : Color.white);
((Graphic)_name).color = style.NameColor;
LayOutMark(style);
}
public void SetSkull(Sprite bone, Sprite holes, float aspect)
{
_skullBoneSprite = bone;
_skullHolesSprite = holes;
_skullAspect = ((aspect > 0f) ? aspect : 1f);
if (_style != null)
{
LayOutMark(_style);
}
}
private void LayOutMark(BarStyle style)
{
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: 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_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: 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_0102: 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_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: 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_0177: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
_eyes.sprite = style.MarkEyes;
if (style.Marks != null)
{
if (style.MarkBehind)
{
((Transform)_markRoot).SetAsFirstSibling();
}
else
{
((Transform)_markRoot).SetSiblingIndex(((Component)_frame).transform.GetSiblingIndex() + 1);
}
((Component)_eyes).transform.SetSiblingIndex(((Component)_frame).transform.GetSiblingIndex() + 1);
_markRoot.anchoredPosition = style.MarkPivot;
RectTransform rectTransform = ((Graphic)_mark).rectTransform;
Rect markRect = style.MarkRect;
Vector2 position = ((Rect)(ref markRect)).position - style.MarkPivot;
markRect = style.MarkRect;
Place(rectTransform, position, ((Rect)(ref markRect)).size);
float skullHeight = style.SkullHeight;
Vector2 size = default(Vector2);
((Vector2)(ref size))..ctor(skullHeight * _skullAspect, skullHeight);
Vector2 position2 = style.SkullCentre - style.MarkPivot;
Quaternion localRotation = Quaternion.Euler(0f, 0f, style.SkullAngle);
Place(((Graphic)_skullBone).rectTransform, position2, size);
Place(((Graphic)_skullHoles).rectTransform, position2, size);
((Transform)((Graphic)_skullBone).rectTransform).localRotation = localRotation;
((Transform)((Graphic)_skullHoles).rectTransform).localRotation = localRotation;
_skullBone.sprite = _skullBoneSprite;
_skullHoles.sprite = _skullHolesSprite;
((Graphic)_skullBone).color = style.SkullBoneColor;
((Graphic)_skullHoles).color = style.SkullHoleColor;
((Behaviour)_skullBone).enabled = skullHeight > 0f && (Object)(object)_skullBoneSprite != (Object)null;
((Behaviour)_skullHoles).enabled = skullHeight > 0f && (Object)(object)_skullHolesSprite != (Object)null && style.SkullHoleColor.a > 0f;
}
}
private static void Place(RectTransform rect, Vector2 position, Vector2 size)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
rect.anchoredPosition = position;
rect.sizeDelta = size;
}
public bool Show(Vector2 position, float scale, float alpha, float health, float trail, string name, int marks)
{
//IL_001f: 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)
if (!_root.activeSelf)
{
_root.SetActive(true);
}
_rootRect.anchoredPosition = position;
((Transform)_rootRect).localScale = new Vector3(scale, scale, 1f);
_group.alpha = alpha;
_fill.fillAmount = _style.FillAmount(health);
_trail.fillAmount = _style.FillAmount(trail);
bool flag = !string.IsNullOrEmpty(name);
if (_nameRoot.activeSelf != flag)
{
_nameRoot.SetActive(flag);
}
if (flag && !string.Equals(_shownName, name, StringComparison.Ordinal))
{
_shownName = name;
((TMP_Text)_name).text = name;
((TMP_Text)_nameShadow).text = name;
}
return ShowMarks(marks, scale);
}
private bool ShowMarks(int marks, float scale)
{
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
bool flag = marks > 0 && _style.Marks != null;
if (((Component)_markRoot).gameObject.activeSelf != flag)
{
((Component)_markRoot).gameObject.SetActive(flag);
}
if (((Behaviour)_eyes).enabled != (flag && (Object)(object)_style.MarkEyes != (Object)null))
{
((Behaviour)_eyes).enabled = flag && (Object)(object)_style.MarkEyes != (Object)null;
}
if (_marksFresh)
{
_marksFresh = false;
}
else if (marks > _shownMarks)
{
_popStart = Time.unscaledTime;
}
_shownMarks = marks;
if (!flag)
{
return false;
}
_mark.sprite = _style.Marks[Mathf.Min(marks, _style.Marks.Length) - 1];
float num = Mathf.Max(1f, 0.65f / Mathf.Max(scale, 0.01f));
float num2 = Time.unscaledTime - _popStart;
if (num2 < 0.2f)
{
num *= 1f + 0.3f * (1f - num2 / 0.2f);
}
((Transform)_markRoot).localScale = new Vector3(num, num, 1f);
return true;
}
public void Hide()
{
_marksFresh = true;
_shownMarks = 0;
_popStart = float.NegativeInfinity;
if (_root.activeSelf)
{
_root.SetActive(false);
}
}
private Image CreateMarkImage(string name)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: 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)
GameObject val = new GameObject(name, new Type[3]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image)
});
val.transform.SetParent((Transform)(object)_markRoot, false);
RectTransform val2 = (RectTransform)val.transform;
val2.anchorMin = Vector2.zero;
val2.anchorMax = Vector2.zero;
val2.pivot = Vector2.zero;
Image component = val.GetComponent<Image>();
((Graphic)component).raycastTarget = false;
return component;
}
private Image CreateImage(string name, bool filled)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name, new Type[3]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image)
});
val.transform.SetParent((Transform)(object)_rootRect, false);
RectTransform val2 = (RectTransform)val.transform;
val2.anchorMin = Vector2.zero;
val2.anchorMax = Vector2.one;
val2.offsetMin = Vector2.zero;
val2.offsetMax = Vector2.zero;
Image component = val.GetComponent<Image>();
((Graphic)component).raycastTarget = false;
if (filled)
{
component.type = (Type)3;
component.fillMethod = (FillMethod)0;
component.fillOrigin = 0;
}
return component;
}
private static TextMeshProUGUI CreateText(string name, Transform parent, Color color, Vector2 offset)
{
//IL_0014: 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_0026: 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_0031: 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_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_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
val.transform.SetParent(parent, false);
RectTransform val2 = (RectTransform)val.transform;
val2.anchorMin = Vector2.zero;
val2.anchorMax = Vector2.one;
val2.offsetMin = offset;
val2.offsetMax = offset;
TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj).alignment = (TextAlignmentOptions)1026;
((TMP_Text)obj).fontSize = 18f;
((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
((Graphic)obj).raycastTarget = false;
((Graphic)obj).color = color;
return obj;
}
}
[BepInPlugin("ryuka.sulfur.enemy_health_bars", "Enemy Health Bars", "0.2.0")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "ryuka.sulfur.enemy_health_bars";
public const string PluginName = "Enemy Health Bars";
public const string PluginVersion = "0.2.0";
internal static ManualLogSource Log;
internal static ConfigEntry<BarDisplayMode> Mode;
internal static ConfigEntry<BarStyleId> Style;
internal static ConfigEntry<float> MaxDistance;
internal static ConfigEntry<float> BarScale;
internal static ConfigEntry<bool> ShowName;
internal static ConfigEntry<bool> DebugLog;
private Harmony _harmony;
private void Awake()
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Expected O, but got Unknown
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Expected O, but got Unknown
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Mode = ((BaseUnityPlugin)this).Config.Bind<BarDisplayMode>("Display", "DisplayMode", BarDisplayMode.Damaged, "Damaged shows a bar for a few seconds after an enemy loses health. Nearby shows a bar on every enemy in range that you can see.");
Style = ((BaseUnityPlugin)this).Config.Bind<BarStyleId>("Display", "BarStyle", BarStyleId.Sulfur, "Look of the bars. Sulfur matches the HUD health bar and follows its color. Rounds is a row of ten rings like the ammo gauge. Ichor is a bar of dripping ink. Bone has a skull at its left end. Classic is a plain bar.");
MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "MaxDistance", 30f, new ConfigDescription("How far away a bar can still show, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()));
BarScale = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "BarScale", 1f, new ConfigDescription("Size of the bars and names.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>()));
ShowName = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowName", true, "Show the enemy's name above its bar.");
DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Write bar events to the log. Doesn't change what you see.");
HealthBarManager.EnsureExists();
_harmony = new Harmony("ryuka.sulfur.enemy_health_bars");
try
{
_harmony.PatchAll(typeof(BossBarTracker));
}
catch (Exception ex)
{
Log.LogError((object)("Could not follow the boss health bar; a boss that is not flagged as one may show two bars: " + ex));
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"Enemy Health Bars 0.2.0 loaded.");
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
_harmony = null;
BossBarTracker.Reset();
HealthBarManager.Shutdown();
BarStyle.Unload();
SkullArt.Unload();
}
}
public enum BarDisplayMode
{
Damaged = 1,
Nearby
}
internal static class SkullArt
{
private enum State
{
NotStarted,
Loading,
TimedOut,
Done
}
private const string SkullUnitName = "BlackGuildSkeleton";
private const float LoadTimeoutSeconds = 20f;
private static State _state;
private static float _loadStartedAt;
private static readonly List<Object> Owned = new List<Object>();
private const int S = 2;
private const float Tilt = 6f;
private const float AlphaCut = 22f / 51f;
public static Sprite Bone { get; private set; }
public static Sprite Holes { get; private set; }
public static float Aspect { get; private set; } = 1f;
public static void Tick()
{
if (_state == State.Done || _state == State.TimedOut)
{
return;
}
if (_state == State.Loading)
{
if (Time.realtimeSinceStartup - _loadStartedAt > 20f)
{
_state = State.TimedOut;
Plugin.Log.LogWarning((object)("The skull portrait did not load in " + 20f + " s; team marks show without the skull until it does."));
}
return;
}
AsyncAssetLoading instance = StaticInstance<AsyncAssetLoading>.Instance;
UnitDatabase val = (((Object)(object)instance != (Object)null) ? instance.unitDatabase : null);
if ((Object)(object)val == (Object)null)
{
return;
}
UnitSO val2 = null;
try
{
foreach (UnitSO raw in val.GetRawList())
{
if ((Object)(object)raw != (Object)null && string.Equals(((Object)raw).name, "BlackGuildSkeleton", StringComparison.Ordinal))
{
val2 = raw;
break;
}
}
}
catch (Exception ex)
{
Finish(null, "unit database: " + ex.Message);
return;
}
if ((Object)(object)val2 == (Object)null)
{
Finish(null, "no unit named BlackGuildSkeleton");
return;
}
_state = State.Loading;
_loadStartedAt = Time.realtimeSinceStartup;
try
{
val2.LoadAndSetArtwork((Action<Sprite>)OnPortrait);
}
catch (Exception ex2)
{
Finish(null, "LoadAndSetArtwork: " + ex2.Message);
}
}
public static void Unload()
{
foreach (Object item in Owned)
{
if (item != (Object)null)
{
Object.Destroy(item);
}
}
Owned.Clear();
Bone = null;
Holes = null;
Aspect = 1f;
_state = State.NotStarted;
}
public static void GiveUp(Exception e)
{
if (_state != State.Done)
{
_state = State.Done;
Plugin.Log.LogWarning((object)("The skull portrait cannot be loaded (" + e.GetType().Name + ": " + e.Message + "); team marks show without the skull."));
}
}
private static void OnPortrait(Sprite portrait)
{
if (_state == State.Loading || _state == State.TimedOut)
{
Finish(portrait, ((Object)(object)portrait == (Object)null) ? "the portrait loaded empty" : null);
}
}
private static void Finish(Sprite portrait, string why)
{
if (_state == State.Done)
{
return;
}
_state = State.Done;
if ((Object)(object)portrait != (Object)null)
{
try
{
CutSkull(portrait, out var bone, out var holes, out var w, out var h);
Bone = MakeSprite(bone, w, h, "EnemyHealthBars.Skull.Bone");
Holes = MakeSprite(holes, w, h, "EnemyHealthBars.Skull.Holes");
Aspect = (float)w / (float)h;
Plugin.Log.LogInfo((object)("Team mark skull cut from " + ((Object)portrait).name + ", " + w + "x" + h + "."));
return;
}
catch (Exception ex)
{
why = ex.GetType().Name + ": " + ex.Message;
Bone = null;
Holes = null;
}
}
Plugin.Log.LogWarning((object)("The skull portrait is unavailable (" + why + "); team marks show without the skull."));
}
private static Sprite MakeSprite(float[] coverage, int w, int h, string name)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: 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_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Expected O, but got Unknown
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
Color32[] array = (Color32[])(object)new Color32[w * h];
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
byte b = (byte)Mathf.Clamp(Mathf.RoundToInt(coverage[i * w + j] * 255f), 0, 255);
array[(h - 1 - i) * w + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
}
}
Texture2D val = new Texture2D(w, h, (TextureFormat)4, true)
{
name = name,
wrapMode = (TextureWrapMode)1,
filterMode = (FilterMode)2,
hideFlags = (HideFlags)61
};
Owned.Add((Object)(object)val);
val.SetPixels32(array);
val.Apply(true, true);
Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)w, (float)h), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
((Object)val2).name = name;
((Object)val2).hideFlags = (HideFlags)61;
Owned.Add((Object)(object)val2);
return val2;
}
private static void CutSkull(Sprite portrait, out float[] bone, out float[] holes, out int w, out int h)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: 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_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
if (portrait.packed && ((int)portrait.packingMode == 0 || (int)portrait.packingRotation != 0))
{
throw new InvalidOperationException("the portrait is tightly packed or rotated in an atlas");
}
int w2;
int h2;
float[] bottomUp = ReadAlpha(portrait, out w2, out h2);
Rect rect = portrait.rect;
float width = ((Rect)(ref rect)).width;
rect = portrait.rect;
float height = ((Rect)(ref rect)).height;
Vector2 textureRectOffset = portrait.textureRectOffset;
float num = width / 256f;
float num2 = height / 256f;
float num3 = height - (textureRectOffset.y + (float)h2);
int W = 340;
int num4 = 280;
bool[] solid = new bool[W * num4];
float num5 = Mathf.Cos((float)Math.PI / 30f);
float num6 = Mathf.Sin((float)Math.PI / 30f);
float num7 = (float)W / 2f;
float num8 = (float)num4 / 2f;
for (int i = 0; i < num4; i++)
{
for (int j = 0; j < W; j++)
{
float num9 = (float)j + 0.5f - num7;
float num10 = (float)i + 0.5f - num8;
float num11 = num9 * num5 + num10 * num6 + num7;
float num12 = (0f - num9) * num6 + num10 * num5 + num8;
float x = (30f + num11 / 2f) * num - textureRectOffset.x;
float y = num12 / 2f * num2 - num3;
solid[i * W + j] = SampleTopLeft(bottomUp, w2, h2, x, y) > 22f / 51f;
}
}
int num13 = num4;
bool flag = false;
for (int k = 0; k < num4; k++)
{
int num14 = -1;
int num15 = -1;
for (int l = 0; l < W; l++)
{
if (solid[k * W + l])
{
if (num14 < 0)
{
num14 = l;
}
num15 = l;
}
}
int num16 = ((num14 >= 0) ? (num15 - num14 + 1) : 0);
if (num16 > 180)
{
flag = true;
}
if (flag && num16 < 110 && k > 140)
{
num13 = k;
break;
}
}
num4 = num13;
bool[] outside = new bool[W * num4];
Stack<int> stack = new Stack<int>();
Action<int, int> action = delegate(int num30, int num29)
{
int num28 = num29 * W + num30;
if (!outside[num28] && !solid[num28])
{
outside[num28] = true;
stack.Push(num28);
}
};
for (int num17 = 0; num17 < W; num17++)
{
action(num17, 0);
action(num17, num4 - 1);
}
for (int num18 = 0; num18 < num4; num18++)
{
action(0, num18);
action(W - 1, num18);
}
while (stack.Count > 0)
{
int num19 = stack.Pop();
int num20 = num19 % W;
int num21 = num19 / W;
if (num20 > 0)
{
action(num20 - 1, num21);
}
if (num20 < W - 1)
{
action(num20 + 1, num21);
}
if (num21 > 0)
{
action(num20, num21 - 1);
}
if (num21 < num4 - 1)
{
action(num20, num21 + 1);
}
}
Bounds(outside, W, num4, out var x2, out var y2, out var x3, out var y3);
int num22 = Math.Min(x3 - x2 + 1, 332);
int num23 = Math.Min(y3 - y2 + 1, 199);
bool[] array = new bool[num22 * num23];
for (int num24 = 0; num24 < num23; num24++)
{
for (int num25 = 0; num25 < num22; num25++)
{
array[num24 * num22 + num25] = !outside[(num24 + y2) * W + num25 + x2];
}
}
bool[] array2 = MainPiece(array, num22, num23, num22 / 2, 20);
Bounds(Invert(array2), num22, num23, out var x4, out var y4, out var x5, out var y5);
w = x5 - x4 + 1;
h = y5 - y4 + 1;
bone = new float[w * h];
holes = new float[w * h];
for (int num26 = 0; num26 < h; num26++)
{
for (int num27 = 0; num27 < w; num27++)
{
if (array2[(num26 + y4) * num22 + num27 + x4])
{
if (solid[(num26 + y4 + y2) * W + num27 + x4 + x2])
{
bone[num26 * w + num27] = 1f;
}
else
{
holes[num26 * w + num27] = 1f;
}
}
}
}
}
private static float[] ReadAlpha(Sprite sprite, out int w, out int h)
{
//IL_0008: 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_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
Texture2D texture = sprite.texture;
Rect textureRect = sprite.textureRect;
w = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
h = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
if (w <= 0 || h <= 0)
{
throw new InvalidOperationException("empty portrait");
}
RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)1);
RenderTexture active = RenderTexture.active;
Texture2D val = null;
try
{
Graphics.Blit((Texture)(object)texture, temporary);
RenderTexture.active = temporary;
val = new Texture2D(w, h, (TextureFormat)4, false, true);
val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)w, (float)h), 0, 0, false);
val.Apply(false);
Color32[] pixels = val.GetPixels32();
float[] array = new float[pixels.Length];
for (int i = 0; i < pixels.Length; i++)
{
array[i] = (float)(int)pixels[i].a / 255f;
}
return array;
}
finally
{
RenderTexture.active = active;
RenderTexture.ReleaseTemporary(temporary);
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
}
}
private static float SampleTopLeft(float[] bottomUp, int w, int h, float x, float y)
{
float num = x - 0.5f;
float num2 = (float)h - y - 0.5f;
int num3 = Mathf.FloorToInt(num);
int num4 = Mathf.FloorToInt(num2);
float num5 = num - (float)num3;
float num6 = num2 - (float)num4;
return Mathf.Lerp(Mathf.Lerp(At(bottomUp, w, h, num3, num4), At(bottomUp, w, h, num3 + 1, num4), num5), Mathf.Lerp(At(bottomUp, w, h, num3, num4 + 1), At(bottomUp, w, h, num3 + 1, num4 + 1), num5), num6);
}
private static float At(float[] m, int w, int h, int x, int y)
{
if (x >= 0 && y >= 0 && x < w && y < h)
{
return m[y * w + x];
}
return 0f;
}
private static bool[] Invert(bool[] m)
{
bool[] array = new bool[m.Length];
for (int i = 0; i < m.Length; i++)
{
array[i] = !m[i];
}
return array;
}
private static void Bounds(bool[] empty, int w, int h, out int x0, out int y0, out int x1, out int y1)
{
x0 = w;
y0 = h;
x1 = -1;
y1 = -1;
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
if (!empty[i * w + j])
{
if (j < x0)
{
x0 = j;
}
if (j > x1)
{
x1 = j;
}
if (i < y0)
{
y0 = i;
}
if (i > y1)
{
y1 = i;
}
}
}
}
if (x1 < 0)
{
throw new InvalidOperationException("no skull in the portrait");
}
}
private static bool[] MainPiece(bool[] m, int w, int h, int sx, int sy)
{
int[] array = new int[m.Length];
int num = 0;
int num2 = 0;
int num3 = 0;
Stack<int> stack = new Stack<int>();
for (int i = 0; i < m.Length; i++)
{
if (!m[i] || array[i] != 0)
{
continue;
}
int num4 = ++num3;
int num5 = 0;
array[i] = num4;
stack.Push(i);
while (stack.Count > 0)
{
int num6 = stack.Pop();
int num7 = num6 % w;
int num8 = num6 / w;
num5++;
if (num7 > 0)
{
Visit(m, array, stack, num6 - 1, num4);
}
if (num7 < w - 1)
{
Visit(m, array, stack, num6 + 1, num4);
}
if (num8 > 0)
{
Visit(m, array, stack, num6 - w, num4);
}
if (num8 < h - 1)
{
Visit(m, array, stack, num6 + w, num4);
}
}
if (num5 > num2)
{
num2 = num5;
num = num4;
}
}
int num9 = ((sx >= 0 && sy >= 0 && sx < w && sy < h) ? array[sy * w + sx] : 0);
int num10 = ((num9 != 0) ? num9 : num);
bool[] array2 = new bool[m.Length];
for (int j = 0; j < m.Length; j++)
{
array2[j] = array[j] == num10;
}
return array2;
}
private static void Visit(bool[] m, int[] label, Stack<int> stack, int k, int id)
{
if (m[k] && label[k] == 0)
{
label[k] = id;
stack.Push(k);
}
}
}
internal sealed class TrackedEnemy
{
public readonly Npc Npc;
public readonly int Id;
public readonly HellShrewSnipa Sniper;
public readonly bool IsGhost;
public readonly CapsuleCollider Collider;
public int SeenInScan;
public float LastHealth;
public float Distance;
public float LastHurtTime = float.NegativeInfinity;
public bool InSight;
public float NextSightCheck;
public float Alpha;
public float Trail;
public string Name;
public HealthBarView View;
public int Marks;
public int MarkDrawnFrame = int.MinValue;
public const float GapAboveHead = 0.2f;
public TrackedEnemy(Npc npc)
{
Npc = npc;
Id = ((Object)npc).GetInstanceID();
Sniper = ((Component)npc).GetComponent<HellShrewSnipa>();
IsGhost = (Object)(object)((Component)npc).GetComponent<GhostHelper>() != (Object)null;
Collider = ((Component)npc).GetComponent<CapsuleCollider>();
LastHealth = ((Unit)npc).normalizedHealth;
Trail = Mathf.Clamp01(LastHealth);
}
public Vector3 Anchor()
{
//IL_001e: 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_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_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_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_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Npc.overhead != (Object)null)
{
return Npc.overhead.position + Vector3.up * 0.2f;
}
if ((Object)(object)Collider != (Object)null && ((Collider)Collider).enabled)
{
Bounds bounds = ((Collider)Collider).bounds;
return ((Bounds)(ref bounds)).center + Vector3.up * (((Bounds)(ref bounds)).extents.y + 0.2f);
}
return ((Component)Npc).transform.position + Vector3.up * 2f;
}
}
}