Decompiled source of WeaponStatsPlus v1.0.0

SulfurWeaponStats.dll

Decompiled 19 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using Microsoft.CodeAnalysis;
using PerfectRandom.Sulfur.Core;
using PerfectRandom.Sulfur.Core.Items;
using PerfectRandom.Sulfur.Core.Stats;
using PerfectRandom.Sulfur.Core.UI.ItemDescription;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[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 SulfurWeaponStats
{
	internal static class FireCycle
	{
		internal static string Text(WeaponSO so, float rpm)
		{
			float num = 60f / rpm;
			bool actionLimited = false;
			if ((Object)(object)so != (Object)null && so.rpm > 0 && ReloadData.Table.TryGetValue(((Object)so).name, out var value) && value.Cycle > 0f)
			{
				float num2 = value.Cycle * (float)so.rpm / rpm;
				if (num2 > num + 0.0005f)
				{
					num = num2;
					actionLimited = true;
				}
			}
			return Strings.FireIntervalValue(num.ToString("0.000"), rpm.ToString("0"), actionLimited);
		}
	}
	internal static class ModifierText
	{
		internal const float BulletBaseMass = 3f;

		internal static readonly MethodInfo AddAttribute = AccessTools.Method(typeof(ItemDescription), "AddAttribute", (Type[])null, (Type[])null);

		private static readonly FieldRef<ItemDescription, ItemDefinition> ItemDefRef = AccessTools.FieldRefAccess<ItemDescription, ItemDefinition>("itemDefinition");

		private static bool _errorLogged;

		internal static ItemDefinition CurrentItem(ItemDescription desc)
		{
			return ItemDefRef.Invoke(desc);
		}

		internal static void LogOnce(Exception e)
		{
			if (!_errorLogged)
			{
				_errorLogged = true;
				Plugin.Log.LogError((object)("Failed to rewrite modifier text: " + e));
			}
		}

		internal static string Label(ItemAttributes attr)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			string result = default(string);
			if (LocalizationManager.TryGetTranslation($"ItemAttributes/{attr}_itemDescription", ref result, true, 0, true, false, (GameObject)null, (string)null, true))
			{
				return result;
			}
			return AssetAccess.GetAsset(attr)?.itemDescriptionName;
		}

		internal static bool IsSimplifiedText(ItemAttributes attr, string text)
		{
			//IL_0000: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			ItemAttribute asset = AssetAccess.GetAsset(attr);
			if ((Object)(object)asset == (Object)null)
			{
				return false;
			}
			string text3 = default(string);
			string text2 = (LocalizationManager.TryGetTranslation($"ItemAttributes/{attr}_simplifiedIncrease", ref text3, true, 0, true, false, (GameObject)null, (string)null, true) ? text3 : asset.simplifiedIncreaseString);
			string text5 = default(string);
			string text4 = (LocalizationManager.TryGetTranslation($"ItemAttributes/{attr}_simplifiedDecrease", ref text5, true, 0, true, false, (GameObject)null, (string)null, true) ? text5 : asset.simplifiedDecreaseString);
			if (!(text == text2))
			{
				return text == text4;
			}
			return true;
		}

		internal static IEnumerable<ItemModifierContainer> Modifiers(ItemDefinition def)
		{
			if ((Object)(object)def == (Object)null)
			{
				yield break;
			}
			if (((EnchantmentId)(ref def.appliesEnchantment)).IsValid)
			{
				EnchantmentDefinition asset = AssetAccess.GetAsset(def.appliesEnchantment);
				if ((Object)(object)asset != (Object)null && asset.modifiersApplied != null)
				{
					foreach (ItemModifierContainer item in asset.modifiersApplied)
					{
						yield return item;
					}
				}
			}
			if (def.modifiersOnAttachToItem == null)
			{
				yield break;
			}
			foreach (ItemModifierContainer item2 in def.modifiersOnAttachToItem)
			{
				yield return item2;
			}
		}

		internal static bool TryGetFlat(ItemDefinition def, ItemAttributes attr, out float value)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			value = 0f;
			bool result = false;
			foreach (ItemModifierContainer item in Modifiers(def))
			{
				if (item.attribute == attr && (int)item.modType == 100)
				{
					value += item.value;
					result = true;
				}
			}
			return result;
		}

		internal static string ForceText(float force)
		{
			return Strings.MuzzleVelocityFactor((1f + force).ToString("0.##"));
		}
	}
	[HarmonyPatch(typeof(ItemDescription), "AddAttribute")]
	internal static class ModifierAttributePatch
	{
		private static void Prefix(ItemDescription __instance, ref string key, ref string value)
		{
			try
			{
				ItemDefinition val = ModifierText.CurrentItem(__instance);
				if (!((Object)(object)val == (Object)null) && !(val is WeaponSO) && !string.IsNullOrEmpty(key))
				{
					if (key == ModifierText.Label((ItemAttributes)41) && value != null && value.StartsWith("x") && float.TryParse(value.Substring(1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						float num = 3f / (3f + result);
						key = Strings.BulletMass;
						value = Strings.BulletMassValue(result.ToString("+0.##;-0.##"), num.ToString("0.##"));
					}
					else if (key == ModifierText.Label((ItemAttributes)61))
					{
						value += Strings.SameTrajectory;
					}
				}
			}
			catch (Exception e)
			{
				ModifierText.LogOnce(e);
			}
		}
	}
	[HarmonyPatch(typeof(ItemDescription), "AddDescriptionText")]
	internal static class ModifierDescriptionPatch
	{
		private static void Prefix(ItemDescription __instance, ref string descriptionText)
		{
			try
			{
				ItemDefinition val = ModifierText.CurrentItem(__instance);
				if (!((Object)(object)val == (Object)null) && !(val is WeaponSO) && !string.IsNullOrEmpty(descriptionText))
				{
					float value2;
					if (ModifierText.IsSimplifiedText((ItemAttributes)65, descriptionText) && ModifierText.TryGetFlat(val, (ItemAttributes)65, out var value))
					{
						descriptionText = Strings.DragLine(value.ToString("+0.##;-0.##"), (0f - value).ToString("+0.##;-0.##"));
					}
					else if (ModifierText.IsSimplifiedText((ItemAttributes)60, descriptionText) && ModifierText.TryGetFlat(val, (ItemAttributes)60, out value2))
					{
						descriptionText = ModifierText.ForceText(value2);
					}
				}
			}
			catch (Exception e)
			{
				ModifierText.LogOnce(e);
			}
		}
	}
	[HarmonyPatch(typeof(ItemDescription), "AddFlavorText")]
	internal static class HiddenForcePatch
	{
		private static void Prefix(ItemDescription __instance, ItemDefinition item, ref int childIndex)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Invalid comparison between Unknown and I4
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Invalid comparison between Unknown and I4
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Invalid comparison between Unknown and I4
			try
			{
				if ((Object)(object)item == (Object)null || item is WeaponSO || !((EnchantmentId)(ref item.appliesEnchantment)).IsValid || ModifierText.AddAttribute == null)
				{
					return;
				}
				ItemAttribute asset = AssetAccess.GetAsset((ItemAttributes)60);
				if ((Object)(object)asset == (Object)null || asset.showInItemDescription)
				{
					return;
				}
				EnchantmentDefinition asset2 = AssetAccess.GetAsset(item.appliesEnchantment);
				if ((Object)(object)asset2 == (Object)null || asset2.modifiersApplied == null)
				{
					return;
				}
				float num = 0f;
				bool flag = false;
				bool flag2 = false;
				foreach (ItemModifierContainer item2 in asset2.modifiersApplied)
				{
					if ((int)item2.attribute == 39)
					{
						flag2 = true;
					}
					if ((int)item2.attribute == 60 && (int)item2.modType == 100)
					{
						num += item2.value;
						flag = true;
					}
				}
				if (!(!flag || flag2))
				{
					object[] array = new object[5]
					{
						Strings.MuzzleVelocity,
						childIndex,
						"x" + (1f + num).ToString("0.##"),
						"",
						false
					};
					ModifierText.AddAttribute.Invoke(__instance, array);
					childIndex = (int)array[1];
				}
			}
			catch (Exception e)
			{
				ModifierText.LogOnce(e);
			}
		}
	}
	[BepInPlugin("ericszh.sulfur.weaponstats", "Weapon Stats Plus", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "ericszh.sulfur.weaponstats";

		public const string Name = "Weapon Stats Plus";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Strings.Language = ((BaseUnityPlugin)this).Config.Bind<Strings.LanguageMode>("General", "Language", Strings.LanguageMode.Auto, "Tooltip language. Auto follows the game language (Chinese if the game is in Chinese, otherwise English).");
			new Harmony("ericszh.sulfur.weaponstats").PatchAll();
			Log.LogInfo((object)"Weapon Stats Plus 1.0.0 loaded.");
		}
	}
	[HarmonyPatch(typeof(ItemDescription), "AddDurability")]
	internal static class AddDurabilityPatch
	{
		private const float Gravity = 20f;

		private const float SpeedCap = 200f;

		private const float DropDistance = 50f;

		private const float LandingHeight = 1.5f;

		private static readonly Dictionary<string, float> ChargeTime = new Dictionary<string, float> { { "Weapon_D4RT", 0.75f } };

		private static readonly MethodInfo AddAttribute = AccessTools.Method(typeof(ItemDescription), "AddAttribute", (Type[])null, (Type[])null);

		private static bool _errorLogged;

		private static void Prefix(ItemDescription __instance, InventoryItem item, ref int childIndex)
		{
			try
			{
				if (!((Object)(object)item == (Object)null) && !(AddAttribute == null))
				{
					WeaponSO weaponDefinition = item.weaponDefinition;
					ItemStats stats = item.stats;
					if (!((Object)(object)weaponDefinition == (Object)null) && stats != null && !weaponDefinition.IsMelee && !weaponDefinition.IsThrowable)
					{
						AddHiddenRpmInterval(__instance, weaponDefinition, stats, ref childIndex);
						AddCharge(__instance, weaponDefinition, stats, ref childIndex);
						AddRecoil(__instance, item, stats, ref childIndex);
						AddBallistics(__instance, weaponDefinition, stats, ref childIndex);
						AddReload(__instance, weaponDefinition, stats, ref childIndex);
					}
				}
			}
			catch (Exception ex)
			{
				if (!_errorLogged)
				{
					_errorLogged = true;
					Plugin.Log.LogError((object)("Failed to add weapon stats: " + ex));
				}
			}
		}

		private static void Add(ItemDescription desc, string key, string value, ref int childIndex)
		{
			object[] array = new object[5] { key, childIndex, value, "", false };
			AddAttribute.Invoke(desc, array);
			childIndex = (int)array[1];
		}

		private static string Mult(float m)
		{
			if (!(Mathf.Abs(m - 1f) > 0.001f))
			{
				return "";
			}
			return $" (x{m:0.##})";
		}

		private static void AddHiddenRpmInterval(ItemDescription desc, WeaponSO so, ItemStats st, ref int childIndex)
		{
			if (so.hideRpm && so.firesByTrigger)
			{
				float attribute = st.GetAttribute((ItemAttributes)56);
				if (!(attribute <= 0f))
				{
					Add(desc, Strings.FireInterval, FireCycle.Text(so, attribute), ref childIndex);
				}
			}
		}

		private static void AddCharge(ItemDescription desc, WeaponSO so, ItemStats st, ref int childIndex)
		{
			if (ChargeTime.TryGetValue(((Object)so).name, out var value) && so.rpm > 0)
			{
				float attribute = st.GetAttribute((ItemAttributes)56);
				if (!(attribute <= 0f))
				{
					float num = value / Mathf.Clamp(attribute / (float)so.rpm, 0.01f, 10f);
					float num2 = num + 60f / attribute;
					Add(desc, Strings.Charge, Strings.ChargeCycle(num.ToString("0.00"), num2.ToString("0.00")), ref childIndex);
				}
			}
		}

		private static void AddRecoil(ItemDescription desc, InventoryItem item, ItemStats st, ref int childIndex)
		{
			float attribute = st.GetAttribute((ItemAttributes)19);
			float num = Mathf.Clamp(attribute * item.KickPower, 0f, 999f);
			Add(desc, Strings.Recoil, num.ToString("0.##") + Mult(attribute), ref childIndex);
		}

		private static void AddBallistics(ItemDescription desc, WeaponSO so, ItemStats st, ref int childIndex)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (st.GetAttribute((ItemAttributes)113) > 0f)
			{
				Add(desc, Strings.BulletSpeed, Strings.Beam, ref childIndex);
				return;
			}
			if ((int)so.projectileType == 4 || st.GetAttribute((ItemAttributes)39) > 0f)
			{
				Add(desc, Strings.BulletSpeed, Strings.Rocket, ref childIndex);
				return;
			}
			ProjectileDefinition asset = AssetAccess.GetAsset(so.projectileType);
			if ((Object)(object)asset == (Object)null)
			{
				return;
			}
			float num = asset.mass + st.GetAttribute((ItemAttributes)41);
			if (num <= 0f)
			{
				return;
			}
			float num2 = so.bulletSpeed * (1f + st.GetAttribute((ItemAttributes)60)) / num;
			float num3 = Mathf.Min(num2, 200f);
			float num4 = Mathf.Clamp(st.GetAttribute((ItemAttributes)61), 0.01f, 10f);
			bool flag = st.GetAttribute((ItemAttributes)62) > 0f;
			string value = ((num2 > 200f) ? $"{num2:0} m/s ({Strings.CappedAt} {200f:0})" : $"{num2:0} m/s");
			Add(desc, Strings.MuzzleVelocity, value, ref childIndex);
			Add(desc, Strings.BulletSpeed, flag ? Strings.Hitscan : $"{num3 * num4:0} m/s", ref childIndex);
			if (!(num3 <= 0.01f))
			{
				float num5 = 20f * asset.gravityFactor * st.GetAttribute((ItemAttributes)102);
				if (!(num5 <= 0f))
				{
					float drag = Mathf.Max(0f, asset.drag + st.GetAttribute((ItemAttributes)65));
					float? num6 = DropAtDistance(num3, drag, num5, 50f);
					string value2 = ((!num6.HasValue) ? "-" : ((num6.Value > 99f) ? ">99 m" : $"{num6.Value:0.0} m"));
					Add(desc, Strings.DropAt(50f), value2, ref childIndex);
					float num7 = DistanceAtDrop(num3, drag, num5, 1.5f);
					Add(desc, Strings.Landing(1.5f), $"{num7:0} m", ref childIndex);
				}
			}
		}

		private static float? DropAtDistance(float v0, float drag, float g, float distance)
		{
			if (drag < 0.0001f)
			{
				float num = distance / v0;
				return 0.5f * g * num * num;
			}
			float num2 = distance * drag / v0;
			if (num2 >= 1f)
			{
				return null;
			}
			float num3 = (0f - Mathf.Log(1f - num2)) / drag;
			return g / drag * (num3 - distance / v0);
		}

		private static float DistanceAtDrop(float v0, float drag, float g, float height)
		{
			if (drag < 0.0001f)
			{
				return v0 * Mathf.Sqrt(2f * height / g);
			}
			float num = 0f;
			float num2 = height * drag / g + 1f / drag;
			for (int i = 0; i < 60; i++)
			{
				float num3 = 0.5f * (num + num2);
				if (g / drag * (num3 - (1f - Mathf.Exp((0f - drag) * num3)) / drag) < height)
				{
					num = num3;
				}
				else
				{
					num2 = num3;
				}
			}
			return v0 * (1f - Mathf.Exp((0f - drag) * num)) / drag;
		}

		private static void AddReload(ItemDescription desc, WeaponSO so, ItemStats st, ref int childIndex)
		{
			if (!ReloadData.Table.TryGetValue(((Object)so).name, out var value))
			{
				return;
			}
			float num = Mathf.Clamp(st.GetAttribute((ItemAttributes)55), 0.01f, 10f);
			string text = Mult(num);
			switch (value.Kind)
			{
			case 1:
			{
				float num4 = value.Empty / num;
				float num5 = ((value.Partial > 0f) ? value.Partial : value.Empty) / num;
				string text3 = $"{num5:0.00} s";
				if (value.EmptyLoaded < value.Mag)
				{
					text3 += Strings.EmptyPartialLoad(num4.ToString("0.00"), value.EmptyLoaded);
				}
				else if (Mathf.Abs(num4 - num5) > 0.05f)
				{
					text3 += Strings.Empty(num4.ToString("0.00"));
				}
				Add(desc, Strings.Reload, text3 + text, ref childIndex);
				break;
			}
			case 2:
			{
				string text2 = Strings.ShellLoad((value.PerShell > 1) ? Strings.PerClip(value.PerShell) : Strings.PerRound, (value.Shell / num).ToString("0.00"), (value.Empty / num).ToString("0.0"));
				Add(desc, Strings.Loading, text2 + text, ref childIndex);
				break;
			}
			case 3:
			{
				float num2 = value.Fixed + value.ShellEvent / num;
				float num3 = value.Fixed + value.Empty / num;
				Add(desc, Strings.Loading, Strings.HoldLoad(num2.ToString("0.00"), value.Mag, num3.ToString("0.0")) + text, ref childIndex);
				break;
			}
			}
		}
	}
	internal readonly struct R
	{
		public readonly int Kind;

		public readonly float Empty;

		public readonly int EmptyLoaded;

		public readonly float Partial;

		public readonly float Start;

		public readonly float Shell;

		public readonly float ShellEvent;

		public readonly int PerShell;

		public readonly float Fixed;

		public readonly int Mag;

		public readonly float Cycle;

		public R(int kind, float empty, int emptyLoaded, float partial, float start, float shell, float shellEvent, int perShell, float fixedPart, int mag, float cycle)
		{
			Kind = kind;
			Empty = empty;
			EmptyLoaded = emptyLoaded;
			Partial = partial;
			Start = start;
			Shell = shell;
			ShellEvent = shellEvent;
			PerShell = perShell;
			Fixed = fixedPart;
			Mag = mag;
			Cycle = cycle;
		}
	}
	internal static class ReloadData
	{
		public static readonly Dictionary<string, R> Table = new Dictionary<string, R>
		{
			{
				"Weapon_Arbiter2",
				new R(1, 3.1f, 3, 3.1f, 0f, 0f, 0f, 0, 0f, 3, 0f)
			},
			{
				"Weapon_Augusta",
				new R(1, 3.117f, 6, 2.717f, 0f, 0f, 0f, 0, 0f, 6, 0.233f)
			},
			{
				"Weapon_Balthazar",
				new R(1, 3.233f, 4, 3.233f, 0f, 0f, 0f, 0, 0f, 4, 0f)
			},
			{
				"Weapon_Beck",
				new R(1, 2.35f, 26, 1.967f, 0f, 0f, 0f, 0, 0f, 26, 0f)
			},
			{
				"Weapon_Blackwater",
				new R(1, 3.6f, 8, 2.917f, 0f, 0f, 0f, 0, 0f, 12, 0f)
			},
			{
				"Weapon_Breacher8",
				new R(3, 4.433f, 8, 0f, 0f, 0.55f, 0.367f, 0, 0.833f, 8, 0f)
			},
			{
				"Weapon_Bronco",
				new R(2, 6.263f, 10, 0f, 0.833f, 0.583f, 0.183f, 1, 0f, 10, 0f)
			},
			{
				"Weapon_CYB47",
				new R(1, 2.983f, 47, 2.983f, 0f, 0f, 0f, 0, 0f, 47, 0f)
			},
			{
				"Weapon_Catacoil",
				new R(1, 2.517f, 30, 2.517f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_Cavalier",
				new R(1, 2.233f, 30, 1.717f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_Chat-Pardeur98",
				new R(1, 4.383f, 20, 4.383f, 0f, 0f, 0f, 0, 0f, 20, 0.167f)
			},
			{
				"Weapon_ChimeraRapid",
				new R(1, 3.217f, 22, 2.25f, 0f, 0f, 0f, 0, 0f, 22, 0f)
			},
			{
				"Weapon_Corpsemaker",
				new R(1, 2.3f, 30, 1.55f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_D4RT",
				new R(1, 1.133f, 1, 1.133f, 0f, 0f, 0f, 0, 0f, 1, 0f)
			},
			{
				"Weapon_DeathStar",
				new R(1, 3.267f, 15, 0f, 0f, 0f, 0f, 0, 0f, 15, 0f)
			},
			{
				"Weapon_DeathsToll",
				new R(2, 1.649f, 4, 0f, 0.5f, 0.333f, 0.15f, 1, 0f, 4, 0f)
			},
			{
				"Weapon_Dirk",
				new R(1, 2.85f, 7, 2.65f, 0f, 0f, 0f, 0, 0f, 7, 0f)
			},
			{
				"Weapon_Dolphin99",
				new R(1, 2.033f, 5, 3.25f, 0f, 0f, 0f, 0, 0f, 5, 2.6f)
			},
			{
				"Weapon_Drifter9",
				new R(1, 2.167f, 20, 2.167f, 0f, 0f, 0f, 0, 0f, 20, 0f)
			},
			{
				"Weapon_Duhar",
				new R(1, 2.567f, 40, 2.567f, 0f, 0f, 0f, 0, 0f, 40, 0f)
			},
			{
				"Weapon_Farsight",
				new R(1, 3.117f, 8, 2.583f, 0f, 0f, 0f, 0, 0f, 8, 0.217f)
			},
			{
				"Weapon_Ferryman",
				new R(1, 4.35f, 20, 3.617f, 0f, 0f, 0f, 0, 0f, 20, 0f)
			},
			{
				"Weapon_FlickerZip",
				new R(1, 2.733f, 5, 0f, 0f, 0f, 0f, 0, 0f, 5, 0f)
			},
			{
				"Weapon_Flock",
				new R(1, 2.983f, 10, 2.567f, 0f, 0f, 0f, 0, 0f, 10, 0f)
			},
			{
				"Weapon_Gravekeeper",
				new R(1, 1.933f, 7, 1.8f, 0f, 0f, 0f, 0, 0f, 7, 0f)
			},
			{
				"Weapon_HellnBack",
				new R(1, 2.95f, 14, 2.717f, 0f, 0f, 0f, 0, 0f, 14, 0f)
			},
			{
				"Weapon_ImpalaGravita",
				new R(1, 2.8f, 8, 2.8f, 0f, 0f, 0f, 0, 0f, 8, 0.75f)
			},
			{
				"Weapon_KleinBauer",
				new R(1, 3.2f, 138, 2.717f, 0f, 0f, 0f, 0, 0f, 138, 0f)
			},
			{
				"Weapon_Knop",
				new R(1, 1f, 1, 1f, 0f, 0f, 0f, 0, 0f, 1, 0.283f)
			},
			{
				"Weapon_LilyOfTheNight",
				new R(1, 3.867f, 70, 3.033f, 0f, 0f, 0f, 0, 0f, 70, 0f)
			},
			{
				"Weapon_Longboy",
				new R(2, 3.183f, 6, 0f, 1.1f, 0.5f, 0.317f, 1, 0f, 6, 0f)
			},
			{
				"Weapon_M11Ramshack",
				new R(1, 2.367f, 30, 1.917f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_Majordome",
				new R(2, 4.748f, 6, 0f, 1f, 0.533f, 0.217f, 1, 0f, 6, 0f)
			},
			{
				"Weapon_Mario",
				new R(1, 2.6f, 2, 2.2f, 0f, 0f, 0f, 0, 0f, 2, 0.25f)
			},
			{
				"Weapon_Mossman",
				new R(2, 4.5f, 6, 0f, 0.667f, 0.5f, 0.267f, 1, 0f, 6, 1.217f)
			},
			{
				"Weapon_Mowlock",
				new R(1, 3.633f, 20, 2.533f, 0f, 0f, 0f, 0, 0f, 20, 0f)
			},
			{
				"Weapon_NeuraxisF22",
				new R(2, 34.817f, 100, 0f, 0.1f, 0.333f, 0.133f, 1, 0f, 100, 0f)
			},
			{
				"Weapon_PalehorseTopclipper",
				new R(1, 2.25f, 7, 2.25f, 0f, 0f, 0f, 0, 0f, 7, 0.917f)
			},
			{
				"Weapon_PierreFusil",
				new R(1, 1.983f, 6, 1.983f, 0f, 0f, 0f, 0, 0f, 6, 0.333f)
			},
			{
				"Weapon_PloikaC",
				new R(1, 2.65f, 40, 1.65f, 0f, 0f, 0f, 0, 0f, 40, 0f)
			},
			{
				"Weapon_RamshackOld_NOT_USED",
				new R(1, 2.583f, 30, 1.683f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_Rektor",
				new R(1, 5.55f, 100, 5.55f, 0f, 0f, 0f, 0, 0f, 100, 0f)
			},
			{
				"Weapon_Rokua",
				new R(1, 2.25f, 5, 2.25f, 0f, 0f, 0f, 0, 0f, 5, 1.283f)
			},
			{
				"Weapon_Salamander",
				new R(1, 2.783f, 8, 2.15f, 0f, 0f, 0f, 0, 0f, 8, 0f)
			},
			{
				"Weapon_Snut38",
				new R(1, 3f, 6, 3f, 0f, 0f, 0f, 0, 0f, 6, 0f)
			},
			{
				"Weapon_Socom9",
				new R(1, 1.85f, 12, 1.417f, 0f, 0f, 0f, 0, 0f, 12, 0f)
			},
			{
				"Weapon_SocomACR",
				new R(1, 3.567f, 42, 3f, 0f, 0f, 0f, 0, 0f, 42, 0f)
			},
			{
				"Weapon_Songbird",
				new R(1, 3.167f, 40, 2.433f, 0f, 0f, 0f, 0, 0f, 40, 0f)
			},
			{
				"Weapon_StarAndWitness",
				new R(1, 3.267f, 30, 1.917f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_TailorMarksman",
				new R(1, 4.2f, 8, 3.733f, 0f, 0f, 0f, 0, 0f, 8, 0f)
			},
			{
				"Weapon_Termite",
				new R(2, 9f, 30, 0f, 0.5f, 0.75f, 0.35f, 3, 0f, 30, 0f)
			},
			{
				"Weapon_TerrierURB",
				new R(1, 2.817f, 14, 2.2f, 0f, 0f, 0f, 0, 0f, 14, 0f)
			},
			{
				"Weapon_Typhoon",
				new R(1, 2.9f, 20, 2.9f, 0f, 0f, 0f, 0, 0f, 20, 0f)
			},
			{
				"Weapon_Unknown",
				new R(1, 2.85f, 10, 2.85f, 0f, 0f, 0f, 0, 0f, 10, 0f)
			},
			{
				"Weapon_Valet",
				new R(1, 2.4f, 24, 1.933f, 0f, 0f, 0f, 0, 0f, 24, 0f)
			},
			{
				"Weapon_Vrede",
				new R(1, 2.567f, 30, 1.817f, 0f, 0f, 0f, 0, 0f, 30, 0f)
			},
			{
				"Weapon_Warpig",
				new R(1, 3.9f, 55, 2.9f, 0f, 0f, 0f, 0, 0f, 55, 0f)
			},
			{
				"Weapon_Wingman",
				new R(1, 3.933f, 18, 1.833f, 0f, 0f, 0f, 0, 0f, 18, 0f)
			},
			{
				"Weapon_WyattPulsar",
				new R(1, 2.15f, 18, 2.15f, 0f, 0f, 0f, 0, 0f, 18, 0f)
			}
		};
	}
	[HarmonyPatch(typeof(ItemDescription), "AddAttribute")]
	internal static class RpmLinePatch
	{
		private static void Prefix(ItemDescription __instance, ref string key, ref string value, ref bool skipSeparator)
		{
			string value2 = Traverse.Create((object)__instance).Field("localizedTextsCache").Field("Label_RPM")
				.GetValue<string>();
			if (!string.IsNullOrEmpty(value2) && !(value != value2) && int.TryParse(key, out var result) && result > 0)
			{
				key = Strings.FireInterval;
				ItemDefinition obj = ModifierText.CurrentItem(__instance);
				value = FireCycle.Text((WeaponSO)(object)((obj is WeaponSO) ? obj : null), result);
				skipSeparator = false;
			}
		}
	}
	internal static class Strings
	{
		internal enum LanguageMode
		{
			Auto,
			English,
			Chinese
		}

		internal static ConfigEntry<LanguageMode> Language;

		private static bool Zh
		{
			get
			{
				switch (Language?.Value ?? LanguageMode.Auto)
				{
				case LanguageMode.English:
					return false;
				case LanguageMode.Chinese:
					return true;
				default:
				{
					string currentLanguageCode = LocalizationManager.CurrentLanguageCode;
					if (!string.IsNullOrEmpty(currentLanguageCode))
					{
						return currentLanguageCode.StartsWith("zh");
					}
					return false;
				}
				}
			}
		}

		public static string Recoil => T("后坐力", "Recoil");

		public static string MuzzleVelocity => T("出膛速度", "Muzzle velocity");

		public static string BulletSpeed => T("弹速", "Bullet speed");

		public static string Beam => T("光束", "Beam");

		public static string Hitscan => T("射线, 瞬间命中", "Hitscan (railgun)");

		public static string Rocket => T("火箭", "Rocket");

		public static string BulletMass => T("子弹质量", "Bullet mass");

		public static string SameTrajectory => T(" (弹道不变)", " (same trajectory)");

		public static string Reload => T("换弹", "Reload");

		public static string Loading => T("装填", "Loading");

		public static string PerRound => T("每发", "per round");

		public static string FireInterval => T("射击间隔", "Fire interval");

		public static string CappedAt => T("上限", "capped at");

		public static string Charge => T("蓄力", "Charge");

		private static string T(string zh, string en)
		{
			if (!Zh)
			{
				return en;
			}
			return zh;
		}

		public static string DropAt(float meters)
		{
			return T($"{meters:0} m 下坠", $"Drop at {meters:0} m");
		}

		public static string Landing(float height)
		{
			return T($"平射落地 ({height:0.#} m 高)", $"Flat shot lands ({height:0.#} m high)");
		}

		public static string BulletMassValue(string mass, string factor)
		{
			return T(mass + " (普通子弹出膛速度 x" + factor + ")", mass + " (regular bullets: muzzle velocity x" + factor + ")");
		}

		public static string DragLine(string drag, string perMeter)
		{
			return T("空气阻力 " + drag + ": 每飞 1 m 速度 " + perMeter + " m/s", "Drag " + drag + ": " + perMeter + " m/s speed per metre flown");
		}

		public static string MuzzleVelocityFactor(string factor)
		{
			return T("出膛速度 x" + factor, "Muzzle velocity x" + factor);
		}

		public static string EmptyPartialLoad(string seconds, int rounds)
		{
			return T($" (打空 {seconds} s, 只装 {rounds} 发)", $" (empty {seconds} s, loads {rounds} only)");
		}

		public static string Empty(string seconds)
		{
			return T(" (打空 " + seconds + " s)", " (empty " + seconds + " s)");
		}

		public static string PerClip(int rounds)
		{
			return T($"每组{rounds}发", $"per {rounds}-round clip");
		}

		public static string ShellLoad(string unit, string per, string full)
		{
			return T(unit + " " + per + " s, 空到满 " + full + " s", per + " s " + unit + ", empty to full " + full + " s");
		}

		public static string HoldLoad(string first, int mag, string full)
		{
			return T($"首发 {first} s, 满 {mag} 发 {full} s", $"first round {first} s, full {mag} rounds {full} s");
		}

		public static string FireIntervalValue(string seconds, string rpm, bool actionLimited)
		{
			if (!actionLimited)
			{
				return seconds + " s (" + rpm + " RPM)";
			}
			return T(seconds + " s (" + rpm + " RPM, 受动作限制)", seconds + " s (" + rpm + " RPM, action-limited)");
		}

		public static string ChargeCycle(string charge, string cycle)
		{
			return T(charge + " s, 每发循环 " + cycle + " s", charge + " s, full cycle " + cycle + " s");
		}
	}
}