using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CellMenu;
using ChainedPuzzles;
using GTFO.API.Utilities;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using Player;
using TMPro;
using TenCC.Utils;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("PreciseUI")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PreciseUI")]
[assembly: AssemblyTitle("PreciseUI")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace Andocas.PreciseUI
{
internal static class BioscanPatches
{
private static CP_Bioscan_Hud? callerBioscanHud;
[HarmonyPatch(typeof(CP_Bioscan_Core), "OnSyncStateChange")]
[HarmonyPostfix]
private static void CP_Bioscan_Core_OnSyncStateChange_Postfix(CP_Bioscan_Core __instance)
{
CP_Bioscan_Graphics val = ((Il2CppObjectBase)__instance.m_graphics).TryCast<CP_Bioscan_Graphics>();
if (ConfigManager.ShowPlayerScaling.Value && val != null && !((TMP_Text)val.m_textMeshRenderer).text.EndsWith("]</size>"))
{
CP_PlayerScanner component = ((Component)__instance).GetComponent<CP_PlayerScanner>();
float[] source = ((!component.m_reqItemsEnabled) ? Il2CppArrayBase<float>.op_Implicit((Il2CppArrayBase<float>)(object)component.m_scanSpeeds) : new float[4]
{
((Il2CppArrayBase<float>)(object)component.m_scanSpeeds)[0],
((Il2CppArrayBase<float>)(object)component.m_scanSpeeds)[0],
((Il2CppArrayBase<float>)(object)component.m_scanSpeeds)[0],
((Il2CppArrayBase<float>)(object)component.m_scanSpeeds)[0]
});
float exitScanMultiplier = 1f;
if (component.IsExitScan && WardenObjectiveManager.Current.m_activeWardenObjectives.ContainsKey((LG_LayerType)0))
{
WardenObjectiveDataBlock val2 = WardenObjectiveManager.Current.m_activeWardenObjectives[(LG_LayerType)0];
exitScanMultiplier = val2.ChainedPuzzleAtExitScanSpeedMultiplier;
}
string[] value = source.Select((float scanSpeed) => (scanSpeed <= 0f) ? "-" : $"{1f / (scanSpeed * exitScanMultiplier):F1}s").ToArray();
TextMeshPro textMeshRenderer = val.m_textMeshRenderer;
((TMP_Text)textMeshRenderer).text = ((TMP_Text)textMeshRenderer).text + "\n<size=70%>[" + string.Join("|", value) + "]</size>";
}
}
[HarmonyPatch(typeof(CP_Bioscan_Hud), "SetVisible")]
[HarmonyAfter(new string[] { "dev.AuriRex.gtfo.TheArchive" })]
[HarmonyPostfix]
private static void CP_Bioscan_Hud_SetVisible_Postfix(CP_Bioscan_Hud __instance, int puzzleIndex, bool visible)
{
if (ConfigManager.ShowChainedPuzzleProgress.Value && visible)
{
int? chainedPuzzleLength = GetChainedPuzzleLength(__instance);
if (chainedPuzzleLength.HasValue && chainedPuzzleLength > 1)
{
__instance.m_atText = $" <#fff>({puzzleIndex + 1}/{chainedPuzzleLength})</color> {Text.Get(1085u)} ";
__instance.m_enterSecurityScanText = $"{Text.Get(1088u)} <#fff>({puzzleIndex + 1}/{chainedPuzzleLength})</color>";
}
}
}
private static int? GetChainedPuzzleLength(CP_Bioscan_Hud targetBioscanHud)
{
foreach (ChainedPuzzleInstance componentsInChild in ((Component)((Component)targetBioscanHud).transform.parent).GetComponentsInChildren<ChainedPuzzleInstance>())
{
foreach (iChainedPuzzleCore item in (Il2CppArrayBase<iChainedPuzzleCore>)(object)componentsInChild.m_chainedPuzzleCores)
{
CP_Bioscan_Core val = ((Il2CppObjectBase)item).TryCast<CP_Bioscan_Core>();
if (val != null)
{
if (((Il2CppObjectBase)val.m_hud).Pointer == ((Il2CppObjectBase)targetBioscanHud).Pointer)
{
return ((Il2CppArrayBase<iChainedPuzzleCore>)(object)componentsInChild.m_chainedPuzzleCores).Length;
}
continue;
}
CP_Cluster_Core val2 = ((Il2CppObjectBase)item).TryCast<CP_Cluster_Core>();
if (val2 != null)
{
CP_Cluster_Hud val3 = ((Il2CppObjectBase)val2.m_hud).TryCast<CP_Cluster_Hud>();
if (val3 != null && ((Il2CppObjectBase)val3.m_hud).Pointer == ((Il2CppObjectBase)targetBioscanHud).Pointer)
{
return ((Il2CppArrayBase<iChainedPuzzleCore>)(object)componentsInChild.m_chainedPuzzleCores).Length;
}
}
}
}
return null;
}
[HarmonyPatch(typeof(CP_Bioscan_Hud), "Update")]
[HarmonyPrefix]
private static void CP_Bioscan_Hud_Update_Prefix_InstanceMarker(CP_Bioscan_Hud __instance)
{
callerBioscanHud = __instance;
}
[HarmonyPatch(typeof(CP_Bioscan_Hud), "Update")]
[HarmonyPostfix]
private static void CP_Bioscan_Hud_Update_Postfix_InstanceMarker()
{
callerBioscanHud = null;
}
[HarmonyPatch(typeof(InteractionGuiLayer), "SetMessage")]
[HarmonyPatch(new Type[]
{
typeof(CharBuffer),
typeof(ePUIMessageStyle),
typeof(int)
})]
[HarmonyPrefix]
private static void InteractionGuiLayer_SetMessage_Prefix(ref CharBuffer buffer)
{
if (callerBioscanHud == null || ((buffer.Length < 2 || ((Il2CppArrayBase<char>)(object)buffer.CharArray)[buffer.Length - 1] != '%') && (buffer.Length < 3 || ((Il2CppArrayBase<char>)(object)buffer.CharArray)[buffer.Length - 2] != '%' || ((Il2CppArrayBase<char>)(object)buffer.CharArray)[buffer.Length - 1] != ' ')))
{
return;
}
CP_PlayerScanner playerScanner = GetPlayerScanner(callerBioscanHud);
if (playerScanner == null)
{
Utils.LogError("Couldn't find CP_PlayerScanner component for " + ((Object)callerBioscanHud).name);
return;
}
float num = CP_PlayerScanner_MasterScan_Emulator(playerScanner);
if (num > 0f)
{
float num2 = (1f - callerBioscanHud.m_progressSmooth) / num;
if (ConfigManager.HudTimerFormat.Value == HudTimerFormats.MinutesAndSeconds || (ConfigManager.HudTimerFormat.Value == HudTimerFormats.Auto && num2 >= 60f))
{
float num3 = Mathf.Ceil(num2);
int value = Mathf.FloorToInt(num3 / 60f);
int value2 = Mathf.FloorToInt(num3 % 60f);
buffer.Set($"{((Object)buffer).ToString().TrimEnd()} ({value:D2}:{value2:D2})");
}
if (ConfigManager.HudTimerFormat.Value == HudTimerFormats.Seconds || (ConfigManager.HudTimerFormat.Value == HudTimerFormats.Auto && num2 < 60f))
{
buffer.Set($"{((Object)buffer).ToString().TrimEnd()} ({num2:F1}<space=0.1em><size=70%>S</size>)");
}
}
}
private static CP_PlayerScanner? GetPlayerScanner(CP_Bioscan_Hud bioscanHud)
{
CP_PlayerScanner result = null;
CP_Cluster_Core component = ((Component)bioscanHud).GetComponent<CP_Cluster_Core>();
CP_Cluster_Hud component2 = ((Component)bioscanHud).GetComponent<CP_Cluster_Hud>();
if (component == null || component2 == null)
{
result = ((Component)bioscanHud).GetComponent<CP_PlayerScanner>();
}
else
{
int num = -1;
int num2 = -1;
for (int i = 0; i < component2.m_clusterSize; i++)
{
if (((Il2CppArrayBase<bool>)(object)component2.m_localPlayerInScan)[i] && ((Il2CppArrayBase<bool>)(object)component2.m_visible)[i])
{
num = i;
num2 = i;
break;
}
if (((Il2CppArrayBase<bool>)(object)component2.m_visible)[i])
{
num2 = i;
}
}
int num3 = ((num >= 0) ? num : ((num2 < 0) ? (-1) : num2));
if (num3 >= 0)
{
CP_Bioscan_Core val = ((Il2CppObjectBase)((Il2CppArrayBase<iChainedPuzzleCore>)(object)component.m_childCores)[num3]).TryCast<CP_Bioscan_Core>();
if (val == null)
{
Utils.LogError($"Cluster '{((Object)component).name}' child {num3} is not a CP_Bioscan_Core!");
}
else
{
result = ((Component)val).GetComponent<CP_PlayerScanner>();
}
}
}
return result;
}
private static float CP_PlayerScanner_MasterScan_Emulator(CP_PlayerScanner playerScanner)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: 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_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: 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)
List<PlayerAgent> list = new List<PlayerAgent>();
float num = 0f;
List<PlayerAgent> playerAgentsInLevel = PlayerManager.PlayerAgentsInLevel;
int count = playerAgentsInLevel.Count;
Vector3 position = ((Component)playerScanner).transform.position;
list.Clear();
for (int i = 0; i < count; i++)
{
if ((Object)(object)playerAgentsInLevel[i] != (Object)null && ((Agent)playerAgentsInLevel[i]).Alive)
{
Vector3 val = position - ((Agent)playerAgentsInLevel[i]).Position;
if (((Vector3)(ref val)).sqrMagnitude < playerScanner.m_scanRadiusSqr)
{
list.Add(playerAgentsInLevel[i]);
}
}
}
int count2 = list.Count;
bool flag = (Extensions.RequireAllPlayers(playerScanner.m_playerRequirement) ? (count2 == count) : ((!Extensions.RequireSoloPlayer(playerScanner.m_playerRequirement)) ? (count2 > 0) : (count2 == 1)));
if (count2 > 0 && count2 - 1 < ((Il2CppArrayBase<float>)(object)playerScanner.m_scanSpeeds).Length)
{
num = ((Il2CppArrayBase<float>)(object)playerScanner.m_scanSpeeds)[count2 - 1];
}
if (flag && playerScanner.m_reqItemsEnabled)
{
num = ((Il2CppArrayBase<float>)(object)playerScanner.m_scanSpeeds)[0];
}
if (flag)
{
if (playerScanner.IsExitScan && WardenObjectiveManager.Current.m_activeWardenObjectives.ContainsKey((LG_LayerType)0))
{
WardenObjectiveDataBlock val2 = WardenObjectiveManager.Current.m_activeWardenObjectives[(LG_LayerType)0];
num *= val2.ChainedPuzzleAtExitScanSpeedMultiplier;
}
if (list != null && list.Count > 0)
{
float num2 = 1f;
for (int j = 0; j < list.Count; j++)
{
num2 += AgentModifierManager.ApplyModifier((Agent)(object)list[j], (AgentModifier)157, 1f) - 1f;
}
num *= Mathf.Max(num2, 0.1f);
}
}
return num;
}
}
internal static class ConfigManager
{
internal static readonly ConfigEntry<int> localplayerstatus_health_precision;
internal static readonly ConfigEntry<int> localplayerstatus_infection_precision;
internal static readonly ConfigEntry<bool> localplayerstatus_infection_sub10_enable;
internal static readonly ConfigEntry<bool> localplayerstatus_infection_rate_enable;
internal static readonly ConfigEntry<int> localplayerstatus_infection_rate_precision;
internal static readonly ConfigEntry<string> localplayerstatus_staminabar_format;
internal static readonly ConfigEntry<int> mapteamstatus_health_precision;
internal static readonly ConfigEntry<int> mapteamstatus_infection_precision;
internal static readonly ConfigEntry<bool> mapteamstatus_infection_sub10_enable;
internal static readonly ConfigEntry<int> inventory_precision;
internal static readonly ConfigEntry<bool> ShowPlayerScaling;
internal static readonly ConfigEntry<bool> ShowChainedPuzzleProgress;
internal static readonly ConfigEntry<HudTimerFormats> HudTimerFormat;
static ConfigManager()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "PreciseUI.cfg"), true);
localplayerstatus_health_precision = val.Bind<int>("Player status bar", "Health precision", 2, "Number of digits after the decimal place");
localplayerstatus_infection_precision = val.Bind<int>("Player status bar", "Infection precision", 2, "Number of digits after the decimal place");
localplayerstatus_infection_sub10_enable = val.Bind<bool>("Player status bar", "Show infection below 10%", true, "Show infection percentage even when infection is less than 10%");
localplayerstatus_infection_rate_enable = val.Bind<bool>("Player status bar", "Show rate of infection", true, "Show the rate at which infection is increasing/decreasing");
localplayerstatus_infection_rate_precision = val.Bind<int>("Player status bar", "Infection rate precision", 2, "Number of digits after the decimal place (assuming \"Show rate of infection\" is enabled)");
localplayerstatus_staminabar_format = val.Bind<string>("Player status bar", "Stamina bar format", "BPM:{heart}{true_bpm:2} | STAM: {stamina:2} <size=80%>{stamina_rate:2}</size> | SPD: {current_speed:2}", "#\r\nWhatever you type here will be displayed between the health bar and the infection bar. Keywords surrounded by curly brackets, e.g. `{vanilla_bpm}`, will be replaced by the appropriate values.\r\n#\r\nMany keywords require rounding. These keywords must be followed by a colon and the desired number of decimal places, e.g. `{stamina:2}`.\r\n#\r\nRecognized keywords:\r\n- {heart}: Heart icon that changes color as pulse increases\r\n- {vanilla_bpm}: Pulse with some random variation, as displayed in vanilla\r\n- {true_bpm:N}: Pulse without any random variation\r\n- {stamina:N}: GTFO's internal stamina measurement, as a percentage from 0% to 100%\r\n- {stamina_rate:N}: The rate at which stamina is being consumed/regenerated per second\r\n- {sprint_speed:N}: Sprinting speed at your current stamina, in meters per second\r\n- {sprint_percent:N}: Sprinting speed at your current stamina, as a percentage of max sprinting speed\r\n- {current_speed:N}: The speed at which you're currently moving, in meters per second\r\n#\r\nYou can type whatever you want. Don't overthink it. For example, `My current pulse is {true_bpm:0} beats per minute` is perfectly valid.\r\n#\r\nFor a vanilla look, set to `PULSE:{heart}{vanilla_bpm}`.\r\n#");
mapteamstatus_health_precision = val.Bind<int>("Team status (map view)", "Health precision", 2, "Number of digits after the decimal place");
mapteamstatus_infection_precision = val.Bind<int>("Team status (map view)", "Infection precision", 2, "Number of digits after the decimal place");
mapteamstatus_infection_sub10_enable = val.Bind<bool>("Team status (map view)", "Show infection below 10%", true, "Show infection percentage even when infection is less than 10%");
inventory_precision = val.Bind<int>("Inventory", "Precision", 0, "Number of digits after the decimal place for your and your teammates' ammo/tool");
ShowPlayerScaling = val.Bind<bool>("Bioscans", "Show player scaling", true, "Indicate how long each bioscan would take to complete with 1, 2, 3, or 4 players");
ShowChainedPuzzleProgress = val.Bind<bool>("Bioscans", "Show chained puzzle progress", true, "Display how many sets of bioscans are in the current alarm");
HudTimerFormat = val.Bind<HudTimerFormats>("Bioscans", "Timer format", HudTimerFormats.Auto, "\r\nDisplay time until completion of current bioscan\r\n- Seconds: Show seconds remaining, e.g. 68.5s\r\n- MinutesAndSeconds: Show MM:SS, e.g. 01:08\r\n- Auto: Switch between Seconds and MinutesAndSeconds automatically depending on the duration\r\n- None: Do not display timer\r\n");
if (((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("dev.gtfomodding.gtfo-api"))
{
Utils.LogInfo("Creating LiveEdit Listener.");
SetupLiveEditListener(val);
}
else
{
Utils.LogInfo("GTFO-API is not loaded. Proceeding without LiveEdit.");
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void SetupLiveEditListener(ConfigFile configFile)
{
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
ConfigFile configFile2 = configFile;
LiveEditListener val = LiveEdit.CreateListener(Path.GetDirectoryName(configFile2.ConfigFilePath), Path.GetFileName(configFile2.ConfigFilePath), false);
val.FileChanged += (LiveEditEventHandler)delegate
{
configFile2.Reload();
};
}
}
internal enum HudTimerFormats
{
Auto,
Seconds,
MinutesAndSeconds,
None
}
internal enum PuzzleProgressFormats
{
Roman,
Arabic,
None
}
internal static class PluginInfo
{
public const string GUID = "Andocas.PreciseUI";
public const string NAME = "PreciseUI";
public const string VERSION = "0.3.2";
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("Andocas.PreciseUI", "PreciseUI", "0.3.2")]
internal class Plugin : BasePlugin
{
private class UnityComponent : MonoBehaviour
{
private void LateUpdate()
{
PUI_Patches.LateUpdateInfectionText();
}
}
public override void Load()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
Utils.LogInfo("Andocas.PreciseUI is loading...");
Harmony val = new Harmony("Andocas.PreciseUI");
val.PatchAll(typeof(PUI_Patches));
val.PatchAll(typeof(BioscanPatches));
((BasePlugin)this).AddComponent<UnityComponent>();
_ = ConfigManager.localplayerstatus_health_precision;
Utils.LogInfo("Andocas.PreciseUI is loaded");
}
}
internal static class PUI_Patches
{
private static float _prefix_stamina;
private static float sprint_stamrate;
private static float sprint_stamrate_update_time;
[HarmonyPatch(typeof(PUI_LocalPlayerStatus), "UpdateHealth")]
[HarmonyPostfix]
private static void UpdateHealth_Postfix(PUI_LocalPlayerStatus __instance, float health)
{
string text = health.ToString("p" + ConfigManager.localplayerstatus_health_precision.Value);
((TMP_Text)__instance.m_healthText).text = text;
((TMP_Text)__instance.m_healthText).enableWordWrapping = false;
((TMP_Text)__instance.m_healthText).enableAutoSizing = true;
((TMP_Text)__instance.m_healthText).fontSizeMin = 0f;
((TMP_Text)__instance.m_healthText).fontSizeMax = 22f;
}
internal static void LateUpdateInfectionText()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
//IL_0056: 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_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Expected O, but got Unknown
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
if ((int)GameStateManager.CurrentStateName != 10)
{
return;
}
PUI_LocalPlayerStatus playerStatus = GuiManager.PlayerLayer.m_playerStatus;
float infection = playerStatus.m_infection;
LocalPlayerAgent val = new LocalPlayerAgent(((Il2CppObjectBase)PlayerManager.GetLocalPlayerAgent()).Pointer);
float num = 0f;
if (ConfigManager.localplayerstatus_infection_rate_enable.Value)
{
EV_TargetData effectVolumeTargetData = ((PlayerAgent)val).EffectVolumeTargetData;
EV_ModificationData val2 = default(EV_ModificationData);
float num2 = 1f;
Enumerator<EffectVolume> enumerator = EffectVolumeManager.volumes.GetEnumerator();
while (enumerator.MoveNext())
{
EffectVolume current = enumerator.Current;
current.Update(ref effectVolumeTargetData, ref val2, num2);
}
num += val2.infection;
if (infection > 0.85f)
{
num -= 0.01f;
}
if (((PlayerAgent)val).Interaction.m_bestSelectedInteract != null && ((Il2CppObjectBase)((PlayerAgent)val).Interaction.m_bestSelectedInteract).ObjectClass == Il2CppClassPointerStore.GetNativeClassPointer(typeof(Interact_DisinfectionStation)))
{
Interact_DisinfectionStation val3 = new Interact_DisinfectionStation(((Il2CppObjectBase)((PlayerAgent)val).Interaction.m_bestSelectedInteract).Pointer);
if (val3.m_station.m_localDisinfectionActive)
{
num -= val3.m_station.m_disinfectSpeed;
}
}
}
string text = infection.ToString("p" + ConfigManager.localplayerstatus_infection_precision.Value);
if (ConfigManager.localplayerstatus_infection_rate_enable.Value && num != 0f)
{
string text2 = num.ToString("p" + ConfigManager.localplayerstatus_infection_rate_precision.Value);
if (num >= 0f)
{
text2 = "+" + text2;
}
text = text + " <size=80%>" + text2 + "/s</size>";
}
((TMP_Text)playerStatus.m_infectionText).text = text;
if (0f < infection && infection <= 0.1f && ConfigManager.localplayerstatus_infection_sub10_enable.Value)
{
((Behaviour)playerStatus.m_infectionText).enabled = true;
((Graphic)playerStatus.m_infectionText).color = playerStatus.m_infectionLow;
((TMP_Text)playerStatus.m_infectionText).fontSize = 14f;
}
else if (0.1f <= infection)
{
((TMP_Text)playerStatus.m_infectionText).fontSize = 18f;
}
}
[HarmonyPatch(typeof(PlayerStamina), "UseRunStamina")]
[HarmonyPrefix]
private static void UpdateSprintStamratePart1(PlayerStamina __instance)
{
_prefix_stamina = __instance.Stamina;
}
[HarmonyPatch(typeof(PlayerStamina), "UseRunStamina")]
[HarmonyPostfix]
private static void UpdateSprintStamratePart2(PlayerStamina __instance, float deltaTime)
{
sprint_stamrate = (__instance.Stamina - _prefix_stamina) / deltaTime;
sprint_stamrate_update_time = Time.time;
}
[HarmonyPatch(typeof(PlayerStamina), "LateUpdate")]
[HarmonyPrefix]
private static void UpdateStaminaTextPart1(PlayerStamina __instance)
{
_prefix_stamina = __instance.Stamina;
}
[HarmonyPatch(typeof(PlayerStamina), "LateUpdate")]
[HarmonyPostfix]
private static void UpdateStaminaTextPart2(PlayerStamina __instance)
{
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
PUI_LocalPlayerStatus playerStatus = GuiManager.PlayerLayer.m_playerStatus;
string value = Regex.Match(((TMP_Text)playerStatus.m_pulseText).text, "<sprite name=\"heartbeat\" color=#[A-Z0-9]{8}>").Value;
float num = (__instance.Stamina - _prefix_stamina) / Time.deltaTime;
if (Time.time - sprint_stamrate_update_time > Time.deltaTime * 5f)
{
sprint_stamrate = 0f;
}
float value2 = num + sprint_stamrate;
float value3 = __instance.MoveSpeedModifier * __instance.PlayerData.runMoveSpeed;
string value4 = ConfigManager.localplayerstatus_staminabar_format.Value;
value4 = value4.Replace("{heart}", value);
value4 = value4.Replace("{vanilla_bpm}", playerStatus.m_randomizedBPM);
value4 = Utils.DoCustomInterpolation(value4, "true_bpm", playerStatus.m_currentBPM, 'N');
value4 = Utils.DoCustomInterpolation(value4, "stamina", __instance.Stamina, 'P');
value4 = Utils.DoCustomInterpolation(value4, "stamina_rate", value2, 'P', "", "/s", always_sign: true);
value4 = Utils.DoCustomInterpolation(value4, "sprint_percent", __instance.MoveSpeedModifier, 'P');
value4 = Utils.DoCustomInterpolation(value4, "sprint_speed", value3, 'N', "", "m/s");
string string_to_interpolate = value4;
Vector3 horizontalVelocity = localPlayerAgent.Locomotion.HorizontalVelocity;
value4 = Utils.DoCustomInterpolation(string_to_interpolate, "current_speed", ((Vector3)(ref horizontalVelocity)).magnitude, 'N', "", "m/s");
((TMP_Text)playerStatus.m_pulseText).text = value4;
((TMP_Text)playerStatus.m_pulseText).enableAutoSizing = false;
}
[HarmonyPatch(typeof(PUI_Inventory), "SetSlotAmmo")]
[HarmonyPostfix]
private static void SetSlotAmmo(PUI_Inventory __instance, InventorySlot slot, float inPackRel)
{
//IL_003f: 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_0068: Unknown result type (might be due to invalid IL or missing references)
if (ConfigManager.inventory_precision.Value != 0)
{
string text = inPackRel.ToString("p" + ConfigManager.inventory_precision.Value);
if (__instance.m_inventorySlots.ContainsKey(slot))
{
((TMP_Text)__instance.m_inventorySlots[slot].m_selected_ammoTotal).text = text;
((TMP_Text)__instance.m_inventorySlots[slot].m_slim_ammoTotal).text = text;
}
}
}
[HarmonyPatch(typeof(PUI_Inventory), "SetHeader")]
[HarmonyPrefix]
private static void SetPageMapInventoryHeader(PUI_Inventory __instance, ref string header)
{
PlayerAgent val = null;
Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
while (enumerator.MoveNext())
{
PlayerAgent current = enumerator.Current;
if ((Object)(object)current.Owner == (Object)(object)__instance.m_owner)
{
val = current;
break;
}
}
if (val != null)
{
string playerName = val.PlayerName;
string text = Math.Clamp(((Dam_SyncedDamageBase)val.Damage).GetHealthRel(), 0f, 1f).ToString("p" + ConfigManager.mapteamstatus_health_precision.Value);
float infection = val.Damage.Infection;
string value = infection.ToString("p" + ConfigManager.mapteamstatus_infection_precision.Value);
if (infection <= 0f)
{
header = playerName + " <color=orange>(" + text + ")</color>";
}
else if (infection <= 0.1f && ConfigManager.mapteamstatus_infection_sub10_enable.Value)
{
header = $"{playerName} <color=orange>({text})</color><color=#33FFBB><size=70%>({value})</size></color>";
}
else
{
header = $"{playerName} <color=orange>({text})</color><color=#00FFA8>({value})</color>";
}
}
}
}
internal static class Utils
{
private static readonly ManualLogSource logger = Logger.CreateLogSource("Andocas.PreciseUI");
public static void LogInfo(object? o)
{
logger.LogInfo((object)GetMessage(o));
}
public static void LogError(object? o)
{
logger.LogError((object)GetMessage(o));
}
private static string GetMessage(object? o)
{
if (o == null)
{
return "No string representation for <null>";
}
return o.ToString() ?? $"No string representation for <{o.GetType()}>";
}
public static void SendLocalMessage(string text)
{
LogInfo("SendLocalMessage: " + text);
GuiManager.PlayerLayer.m_gameEventLog.AddLogItem(text, (eGameEventChatLogType)2);
CM_PageLoadout.Current.m_gameEventLog.AddLogItem(text, (eGameEventChatLogType)2);
}
public static void SendChatMessage(string text)
{
LogInfo("SendChatMessage: " + text);
string text2 = "<#ff0>";
int num = 50 - text2.Length;
while (text.Length > num)
{
PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text2 + text.Substring(0, num).Trim(), (PlayerAgent)null);
text = text.Substring(num).Trim();
}
PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text2 + text, (PlayerAgent)null);
}
public static string DoCustomInterpolation(string string_to_interpolate, string key, float value, char format_specifier, string prefix = "", string suffix = "", bool always_sign = false)
{
string prefix2 = prefix;
string suffix2 = suffix;
return Regex.Replace(string_to_interpolate, "{" + key + ":([0-9]+)}", ReplaceOneInstance);
string ReplaceOneInstance(Match match)
{
string text = "";
if (always_sign && value >= 0f)
{
text = "+";
}
return prefix2 + text + value.ToString(format_specifier + match.Groups[1].Value) + suffix2;
}
}
}
}