Decompiled source of CrudeChemistry v0.1.4

BepInEx/plugins/CrudeChemistry/CrudeChemistry.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CrudeChemistry;

internal static class BombArtwork
{
	private static AssetBundle bundle;

	private static bool attempted;

	private static string Folder => Path.GetDirectoryName(typeof(Plugin).Assembly.Location);

	internal static Sprite Icon(string id)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Expected O, but got Unknown
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		string path = Path.Combine(Folder, id + "-128.png");
		if (!File.Exists(path))
		{
			return null;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		if (!(bool)typeof(ImageConversion).GetMethod("LoadImage", new Type[3]
		{
			typeof(Texture2D),
			typeof(byte[]),
			typeof(bool)
		}).Invoke(null, new object[3]
		{
			val,
			File.ReadAllBytes(path),
			false
		}))
		{
			Object.Destroy((Object)(object)val);
			return null;
		}
		((Object)val).name = id + "_Icon";
		((Texture)val).filterMode = (FilterMode)0;
		return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
	}

	internal static void Model(GameObject target, string id)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Invalid comparison between Unknown and I4
		//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_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: 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_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: 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_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f8: Expected O, but got Unknown
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		if ((int)SystemInfo.graphicsDeviceType == 4)
		{
			return;
		}
		if (!attempted)
		{
			attempted = true;
			string text = Path.Combine(Folder, "crudechemistry-art");
			if (File.Exists(text))
			{
				bundle = AssetBundle.LoadFromFile(text);
			}
		}
		if (!Object.op_Implicit((Object)(object)bundle))
		{
			return;
		}
		GameObject val = bundle.LoadAsset<GameObject>(("Assets/Collection/" + id + "/" + id + ".prefab").ToLowerInvariant());
		if (!Object.op_Implicit((Object)(object)val))
		{
			return;
		}
		MeshRenderer val2 = ((IEnumerable<MeshRenderer>)target.GetComponentsInChildren<MeshRenderer>(true)).FirstOrDefault((Func<MeshRenderer, bool>)((MeshRenderer r) => Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>()) && Object.op_Implicit((Object)(object)((Component)r).GetComponent<MeshFilter>().sharedMesh)));
		if (!Object.op_Implicit((Object)(object)val2))
		{
			return;
		}
		Bounds bounds = ((Component)val2).GetComponent<MeshFilter>().sharedMesh.bounds;
		GameObject val3 = Object.Instantiate<GameObject>(val, ((Component)val2).transform, false);
		((Object)val3).name = id + "_Artwork";
		MeshFilter componentInChildren = val3.GetComponentInChildren<MeshFilter>();
		if (!Object.op_Implicit((Object)(object)componentInChildren))
		{
			Object.Destroy((Object)(object)val3);
			return;
		}
		float y = ((Bounds)(ref bounds)).size.y;
		Bounds bounds2 = componentInChildren.sharedMesh.bounds;
		float num = y / ((Bounds)(ref bounds2)).size.y;
		val3.transform.localScale = Vector3.one * num;
		Transform transform = val3.transform;
		Vector3 center = ((Bounds)(ref bounds)).center;
		Bounds bounds3 = componentInChildren.sharedMesh.bounds;
		transform.localPosition = center - ((Bounds)(ref bounds3)).center * num;
		Material val4 = ((IEnumerable<Material>)((Renderer)val2).sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m)));
		if (Object.op_Implicit((Object)(object)val4))
		{
			MeshRenderer[] componentsInChildren = val3.GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val5 in componentsInChildren)
			{
				Material[] sharedMaterials = ((Renderer)val5).sharedMaterials;
				for (int num3 = 0; num3 < sharedMaterials.Length; num3++)
				{
					Texture mainTexture = sharedMaterials[num3].mainTexture;
					Material val6 = new Material(val4);
					((Object)val6).name = id + "_NativeMaterial_" + num3;
					val6.mainTexture = mainTexture;
					if (val6.HasProperty("_Color"))
					{
						val6.color = Color.white;
					}
					sharedMaterials[num3] = val6;
				}
				((Renderer)val5).sharedMaterials = sharedMaterials;
			}
		}
		((Renderer)val2).enabled = false;
	}
}
internal static class BombIcons
{
	public static Sprite Create(Sprite original, BombSpec spec)
	{
		//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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		Texture2D texture = original.texture;
		Rect textureRect = original.textureRect;
		RenderTexture active = RenderTexture.active;
		RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
		Texture2D val = null;
		try
		{
			Graphics.Blit((Texture)(object)texture, temporary);
			RenderTexture.active = temporary;
			val = new Texture2D((int)((Rect)(ref textureRect)).width, (int)((Rect)(ref textureRect)).height, (TextureFormat)4, false);
			val.ReadPixels(textureRect, 0, 0);
			int num = Mathf.Max(1, Mathf.Min(((Texture)val).width, ((Texture)val).height) / 24);
			int num2 = ((Texture)val).width - 9 * num;
			int num3 = 2 * num;
			string[] array = Glyph(spec.Id);
			for (int i = 0; i < 9 * num; i++)
			{
				for (int j = 0; j < 7 * num; j++)
				{
					bool flag = j < num || i < num || j >= 6 * num || i >= 8 * num;
					val.SetPixel(num2 + j, num3 + i, flag ? Color.black : spec.Colour);
				}
			}
			for (int k = 0; k < 7; k++)
			{
				for (int l = 0; l < 5; l++)
				{
					if (array[k][l] != '#')
					{
						continue;
					}
					for (int m = 0; m < num; m++)
					{
						for (int n = 0; n < num; n++)
						{
							val.SetPixel(num2 + (l + 1) * num + n, num3 + (7 - k) * num + m, Color.white);
						}
					}
				}
			}
			((Object)val).name = spec.Id + "_IconTexture";
			val.Apply(false, true);
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), original.pixelsPerUnit);
			((Object)val2).name = spec.Id + "_Icon";
			return val2;
		}
		catch
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				Object.Destroy((Object)(object)val);
			}
			throw;
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
		}
	}

	internal static string[] Glyph(string id)
	{
		return id switch
		{
			"CC_ShatterBomb" => new string[7] { ".###.", "#....", "#....", ".###.", "....#", "....#", "####." }, 
			"CC_FrostFlask" => new string[7] { "#####", "#....", "#....", "####.", "#....", "#....", "#...." }, 
			"CC_LeechFlask" => new string[7] { "#....", "#....", "#....", "#....", "#....", "#....", "#####" }, 
			_ => new string[7] { "####.", "#...#", "#...#", "####.", "#.#..", "#..#.", "#...#" }, 
		};
	}
}
internal sealed class BombSpec
{
	public string Id;

	public string Name;

	public string Description;

	public string Icon;

	public float Radius;

	public float Pierce;

	public float Blunt;

	public float Frost;

	public float Poison;

	public bool Cloud;

	public Color Colour;

	public Dictionary<string, int> Ingredients;

	public static readonly BombSpec[] All = new BombSpec[4]
	{
		new BombSpec
		{
			Id = "CC_ShatterBomb",
			Name = "Crystal Shatter Bomb",
			Icon = "Crystal",
			Description = "A corked vial packed with crystal splinters. A single burst deals 45 pierce and 15 blunt base damage within 4 metres.",
			Pierce = 45f,
			Blunt = 15f,
			Radius = 4f,
			Colour = new Color(0.7f, 0.95f, 1f),
			Ingredients = new Dictionary<string, int>
			{
				{ "BlobVial", 1 },
				{ "Crystal", 2 },
				{ "Stone", 2 },
				{ "IronScrap", 1 }
			}
		},
		new BombSpec
		{
			Id = "CC_FrostFlask",
			Name = "Frost Flask",
			Icon = "FreezeGland",
			Description = "Shatters in a brief freezing burst. Deals 25 base frost damage within 4 metres; Valheim determines the resulting frost slow and resistance.",
			Frost = 25f,
			Radius = 4f,
			Colour = new Color(0.2f, 0.55f, 1f),
			Ingredients = new Dictionary<string, int>
			{
				{ "BlobVial", 1 },
				{ "FreezeGland", 2 },
				{ "Crystal", 1 },
				{ "Resin", 2 }
			}
		},
		new BombSpec
		{
			Id = "CC_LeechFlask",
			Name = "Leech Flask",
			Icon = "Bloodbag",
			Description = "A sticky swamp concoction. Deals 5 base blunt damage within 4 metres and reduces movement by 25% for 4 seconds. Repeated hits refresh the slow; they do not stack it.",
			Blunt = 5f,
			Radius = 4f,
			Colour = new Color(0.6f, 0.12f, 0.2f),
			Ingredients = new Dictionary<string, int>
			{
				{ "BlobVial", 1 },
				{ "Bloodbag", 2 },
				{ "ElderBark", 1 },
				{ "Ooze", 1 }
			}
		},
		new BombSpec
		{
			Id = "CC_RotBomb",
			Name = "Rot Bomb",
			Icon = "Ooze",
			Description = "Concentrated rot in a glass vial. Leaves a smaller, six-second poison cloud with 50 base poison damage per exposure. Uses native poison rules, not additive damage every second.",
			Poison = 50f,
			Radius = 3.5f,
			Cloud = true,
			Colour = new Color(0.45f, 0.65f, 0.12f),
			Ingredients = new Dictionary<string, int>
			{
				{ "BlobVial", 1 },
				{ "Ooze", 2 },
				{ "Entrails", 2 },
				{ "Resin", 2 }
			}
		}
	};

	public DamageTypes Damage(float scale)
	{
		//IL_0002: 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)
		return new DamageTypes
		{
			m_pierce = Pierce * scale,
			m_blunt = Blunt * scale,
			m_frost = Frost * scale,
			m_poison = Poison * scale
		};
	}
}
[HarmonyPatch(typeof(ItemStand), "SetVisualItem")]
internal static class BombStandArtwork
{
	private static void Postfix(ItemStand __instance, int __0, GameObject ___m_visualItem)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Invalid comparison between Unknown and I4
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)___m_visualItem) || (int)__instance.m_orientationType != 2)
		{
			return;
		}
		BombSpec spec = BombSpec.All.FirstOrDefault((BombSpec s) => StringExtensionMethods.GetStableHashCode(s.Id) == __0);
		if (spec == null)
		{
			return;
		}
		Transform val = ((IEnumerable<Transform>)___m_visualItem.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == spec.Id + "_Artwork"));
		if (Object.op_Implicit((Object)(object)val))
		{
			MeshFilter componentInChildren = ((Component)val).GetComponentInChildren<MeshFilter>();
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				Quaternion val2 = (val.rotation = ((Component)__instance).transform.rotation);
				Transform parent = ___m_visualItem.transform.parent;
				Bounds bounds = componentInChildren.sharedMesh.bounds;
				float x = ((Bounds)(ref bounds)).center.x;
				Bounds bounds2 = componentInChildren.sharedMesh.bounds;
				float y = ((Bounds)(ref bounds2)).min.y;
				Bounds bounds3 = componentInChildren.sharedMesh.bounds;
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(x, y, ((Bounds)(ref bounds3)).center.z);
				val.position = parent.position - val2 * Vector3.Scale(val3, val.lossyScale);
			}
		}
	}
}
[BepInPlugin("au.tyvalheim.crudechemistry", "Crude Chemistry", "0.1.4")]
public sealed class Plugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	private static class DatabaseAwake
	{
		private static void Prefix(ObjectDB __instance)
		{
			Instance.Register(__instance);
		}

		private static void Postfix()
		{
			Instance.SyncNetwork(ZNetScene.instance);
		}
	}

	[HarmonyPatch(typeof(Aoe), "ShouldHit")]
	private static class SelfHit
	{
		private static void Postfix(Aoe __instance, Collider __0, Character ___m_owner, ref bool __result)
		{
			if (Object.op_Implicit((Object)(object)___m_owner) && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<ChemistryBlast>()))
			{
				GameObject val = Projectile.FindHitObject(__0);
				if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.GetComponent<Character>() == (Object)(object)___m_owner)
				{
					__result = !__instance.m_dodgeable || !___m_owner.IsDodgeInvincible();
				}
			}
		}
	}

	[HarmonyPatch(typeof(Humanoid), "EquipItem")]
	private static class SelectedBombMessage
	{
		private static void Prefix(ItemData __0, out bool __state)
		{
			__state = __0?.m_equipped ?? false;
		}

		private static void Postfix(Humanoid __instance, ItemData __0, bool __result, bool __state)
		{
			if (__result && !__state && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && __0 != null && Object.op_Implicit((Object)(object)__0.m_dropPrefab))
			{
				BombSpec bombSpec = BombSpec.All.FirstOrDefault((BombSpec s) => s.Id == ((Object)__0.m_dropPrefab).name);
				if (bombSpec != null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, "Selected: " + bombSpec.Name, 0, __0.GetIcon(), false);
				}
			}
		}
	}

	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	private static class DatabaseCopy
	{
		private static void Postfix(ObjectDB __instance)
		{
			Instance.Register(__instance);
			AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null).Invoke(__instance, null);
			Instance.SyncNetwork(ZNetScene.instance);
		}
	}

	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	private static class NetworkPrefabs
	{
		private static void Prefix(ZNetScene __instance)
		{
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				Instance.Register(ObjectDB.instance);
			}
			if (!Instance.built)
			{
				return;
			}
			foreach (GameObject prefab in Instance.prefabs)
			{
				if (!__instance.m_prefabs.Contains(prefab))
				{
					__instance.m_prefabs.Add(prefab);
				}
			}
		}

		private static void Postfix(ZNetScene __instance)
		{
			Instance.SyncNetwork(__instance);
		}
	}

	public const string Id = "au.tyvalheim.crudechemistry";

	public const string Version = "0.1.4";

	internal static Plugin Instance;

	private GameObject root;

	private readonly List<GameObject> prefabs = new List<GameObject>();

	private readonly List<Recipe> recipes = new List<Recipe>();

	private SE_Stats leech;

	private bool built;

	private bool failed;

	private ConfigEntry<float> damageScale;

	private ConfigEntry<int> stackSize;

	private ConfigEntry<bool> craftable;

	private ConfigEntry<float> throwSpeed;

	private ConfigEntry<float> throwGravity;

	private ConfigEntry<float> throwLoft;

	private ConfigEntry<bool> useNativeThrow;

	private static readonly MethodInfo Memberwise = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null);

	private void Awake()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Expected O, but got Unknown
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Expected O, but got Unknown
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Expected O, but got Unknown
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Expected O, but got Unknown
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		damageScale = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "DamageMultiplier", 1f, new ConfigDescription("Restart required. Use the same value on every client and server.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), new object[0]));
		stackSize = ((BaseUnityPlugin)this).Config.Bind<int>("Balance", "MaximumStackSize", 10, new ConfigDescription("Restart required. Keep identical across the session.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[0]));
		craftable = ((BaseUnityPlugin)this).Config.Bind<bool>("Crafting", "EnableRecipes", true, "Restart required. Disabling recipes keeps existing items registered.");
		useNativeThrow = ((BaseUnityPlugin)this).Config.Bind<bool>("Throwing", "UseNativeThrow", true, "Use the installed game's native Ooze Bomb throwing behaviour, including speed, gravity, aim spread and launch angle. Ignores the custom throwing values below, including saved 0.1.1 values. Restart required.");
		throwSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Throwing", "Speed", 22f, new ConfigDescription("Custom mode only (UseNativeThrow=false): launch speed in metres/second. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 35f), new object[0]));
		throwGravity = ((BaseUnityPlugin)this).Config.Bind<float>("Throwing", "Gravity", 9f, new ConfigDescription("Custom mode only: downward acceleration. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 20f), new object[0]));
		throwLoft = ((BaseUnityPlugin)this).Config.Bind<float>("Throwing", "UpwardAngle", 12f, new ConfigDescription("Custom mode only: degrees of upward loft added to aim. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), new object[0]));
		root = new GameObject("CrudeChemistry_Prefabs");
		root.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)root);
		new Harmony("au.tyvalheim.crudechemistry").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Crude Chemistry 0.1.4 test build. New items require this mod on all clients and servers.");
	}

	private GameObject Clone(GameObject source, string name)
	{
		if (!Object.op_Implicit((Object)(object)source))
		{
			throw new InvalidOperationException("Missing source for " + name);
		}
		GameObject val = Object.Instantiate<GameObject>(source, root.transform, false);
		((Object)val).name = name;
		val.SetActive(true);
		prefabs.Add(val);
		return val;
	}

	private void Build(ObjectDB db)
	{
		if (built || failed)
		{
			return;
		}
		GameObject val = ((IEnumerable<GameObject>)db.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == "BombOoze"));
		if (Object.op_Implicit((Object)(object)val))
		{
			if (!db.m_items.Any((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == "BlobVial"))
			{
				throw new InvalidOperationException("Corked Vial (BlobVial) is missing. This build targets Valheim 1.0.16.");
			}
			leech = ScriptableObject.CreateInstance<SE_Stats>();
			((Object)leech).name = "CC_LeechSlow";
			((StatusEffect)leech).m_name = "Leech-slick";
			((StatusEffect)leech).m_tooltip = "Movement speed reduced by 25%.";
			((StatusEffect)leech).m_ttl = 4f;
			leech.m_speedModifier = -0.25f;
			((StatusEffect)leech).m_icon = Item(db, "Bloodbag").m_itemData.m_shared.m_icons[0];
			BombSpec[] all = BombSpec.All;
			foreach (BombSpec spec in all)
			{
				BuildBomb(db, val, spec);
			}
			built = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Created four vial recipes and isolated native bomb/item/effect prefabs.");
		}
	}

	private static ItemDrop Item(ObjectDB db, string name)
	{
		GameObject val = ((IEnumerable<GameObject>)db.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => Object.op_Implicit((Object)(object)x) && ((Object)x).name == name));
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.GetComponent<ItemDrop>()))
		{
			throw new InvalidOperationException("Missing ingredient: " + name);
		}
		return val.GetComponent<ItemDrop>();
	}

	private void BuildBomb(ObjectDB db, GameObject source, BombSpec spec)
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected O, but got Unknown
		//IL_010d: 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)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Invalid comparison between Unknown and I4
		//IL_0271: 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_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0610: Unknown result type (might be due to invalid IL or missing references)
		//IL_0615: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0465: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Expected O, but got Unknown
		//IL_055a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0567: Unknown result type (might be due to invalid IL or missing references)
		//IL_0574: Unknown result type (might be due to invalid IL or missing references)
		ItemDrop original = source.GetComponent<ItemDrop>();
		GameObject val = Clone(source, spec.Id);
		ItemDrop component = val.GetComponent<ItemDrop>();
		component.m_itemData = original.m_itemData.Clone();
		component.m_itemData.m_shared = (SharedData)Memberwise.Invoke(original.m_itemData.m_shared, null);
		SharedData shared = component.m_itemData.m_shared;
		shared.m_attack = original.m_itemData.m_shared.m_attack.Clone();
		shared.m_secondaryAttack = original.m_itemData.m_shared.m_secondaryAttack.Clone();
		shared.m_name = spec.Name;
		shared.m_description = spec.Description + "\nConsumes one corked vial per bomb. No building or terrain damage.";
		shared.m_maxStackSize = stackSize.Value;
		shared.m_weight = 0.5f;
		shared.m_maxQuality = 1;
		shared.m_damages = default(DamageTypes);
		shared.m_damagesPerLevel = default(DamageTypes);
		shared.m_attackStatusEffect = null;
		shared.m_attackForce = 0f;
		shared.m_backstabBonus = 1f;
		shared.m_icons = (Sprite[])original.m_itemData.m_shared.m_icons.Clone();
		if ((int)SystemInfo.graphicsDeviceType != 4)
		{
			try
			{
				shared.m_icons[0] = BombArtwork.Icon(spec.Id) ?? BombIcons.Create(shared.m_icons[0], spec);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Using native grenade icon for " + spec.Name + ": " + ex.Message));
			}
		}
		component.m_itemData.m_dropPrefab = val;
		component.m_itemData.m_stack = 1;
		GameObject val2 = Clone(shared.m_attack.m_attackProjectile, spec.Id + "_Projectile");
		Projectile component2 = val2.GetComponent<Projectile>();
		if (!Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component2.m_spawnOnHit) || !Object.op_Implicit((Object)(object)component2.m_spawnOnHit.GetComponent<Aoe>()))
		{
			throw new InvalidOperationException("Native ooze bomb no longer has the expected projectile/Aoe chain.");
		}
		GameObject val3 = Clone(component2.m_spawnOnHit, spec.Id + "_Explosion");
		Aoe component3 = val3.GetComponent<Aoe>();
		component3.m_useAttackSettings = false;
		component3.m_damage = spec.Damage(damageScale.Value);
		component3.m_damagePerLevel = default(DamageTypes);
		component3.m_radius = spec.Radius;
		component3.m_ttl = (spec.Cloud ? 6f : 0.35f);
		component3.m_ttlMax = 0f;
		component3.m_hitInterval = (spec.Cloud ? 1f : 0f);
		component3.m_activationDelay = 0f;
		component3.m_hitOnEnable = false;
		component3.m_hitAfterTtl = false;
		component3.m_useTriggers = false;
		component3.m_useCollider = null;
		component3.m_hitOwner = true;
		val3.AddComponent<ChemistryBlast>();
		component3.m_hitFriendly = false;
		component3.m_hitEnemy = true;
		component3.m_hitCharacters = true;
		component3.m_hitProps = false;
		component3.m_hitTerrain = false;
		component3.m_ignorePVP = true;
		component3.m_attackForce = ((spec.Id == "CC_ShatterBomb") ? 20f : 0f);
		component3.m_backstabBonus = 1f;
		component3.m_canRaiseSkill = false;
		component3.m_statusEffect = ((spec.Id == "CC_LeechFlask") ? "CC_LeechSlow" : "");
		component3.m_statusEffectIfBoss = "";
		component3.m_statusEffectIfPlayer = "";
		component3.m_spawnOnHitTerrain = null;
		component3.m_chainObj = null;
		component3.m_multiSpawnMin = (component3.m_multiSpawnMax = 0);
		component2.m_spawnOnHit = val3;
		component2.m_spawnOffset = Vector3.zero;
		component2.m_damage = default(DamageTypes);
		component2.m_statusEffect = "";
		component2.m_aoe = 0f;
		component2.m_attackForce = 0f;
		component2.m_onlySpawnedProjectilesDealDamage = true;
		component2.m_hitFriendly = false;
		component2.m_noDamageFriendly = true;
		component2.m_respawnItemOnHit = false;
		component2.m_randomSpawnOnHit = new List<GameObject>();
		component2.m_spawnCount = 1;
		component2.m_spawnOnHitChance = 1f;
		EffectList val4 = new EffectList();
		val4.m_effectPrefabs = component2.m_hitEffects.m_effectPrefabs.Where((EffectData e) => Object.op_Implicit((Object)(object)e.m_prefab) && ((Object)e.m_prefab).name.StartsWith("sfx_", StringComparison.Ordinal)).ToArray();
		component2.m_hitEffects = val4;
		shared.m_attack.m_attackProjectile = val2;
		shared.m_attack.m_consumeItem = true;
		if (!useNativeThrow.Value)
		{
			component2.m_gravity = throwGravity.Value;
			shared.m_attack.m_projectileVel = throwSpeed.Value;
			shared.m_attack.m_projectileVelMin = throwSpeed.Value;
			shared.m_attack.m_launchAngle = 0f - throwLoft.Value;
			shared.m_attack.m_projectileAccuracy = 0f;
			shared.m_attack.m_projectileAccuracyMin = 0f;
		}
		shared.m_attack.m_attackStamina = 10f;
		Tint(val, spec.Colour);
		Tint(val2, spec.Colour);
		Tint(val3, spec.Colour);
		try
		{
			BombArtwork.Model(val, spec.Id);
			BombArtwork.Model(val2, spec.Id);
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Custom artwork unavailable for " + spec.Name + ": " + ex2.Message));
		}
		if (!spec.Cloud)
		{
			Renderer[] componentsInChildren = val3.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val5 in componentsInChildren)
			{
				val5.enabled = false;
			}
			ParticleSystem[] componentsInChildren2 = val3.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val6 in componentsInChildren2)
			{
				EmissionModule emission = val6.emission;
				((EmissionModule)(ref emission)).enabled = false;
			}
		}
		Recipe val7 = ScriptableObject.CreateInstance<Recipe>();
		((Object)val7).name = "Recipe_" + spec.Id;
		val7.m_item = component;
		val7.m_amount = 1;
		val7.m_enabled = craftable.Value;
		val7.m_minStationLevel = 1;
		Recipe val8 = ((IEnumerable<Recipe>)db.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => Object.op_Implicit((Object)(object)r) && (Object)(object)r.m_item == (Object)(object)original && Object.op_Implicit((Object)(object)r.m_craftingStation)));
		if (!Object.op_Implicit((Object)(object)val8))
		{
			throw new InvalidOperationException("Missing native ooze bomb crafting station.");
		}
		val7.m_craftingStation = val8.m_craftingStation;
		val7.m_resources = spec.Ingredients.Select(delegate(KeyValuePair<string, int> x)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			Requirement val9 = new Requirement();
			val9.m_resItem = Item(db, x.Key);
			val9.m_amount = x.Value;
			val9.m_amountPerLevel = 0;
			val9.m_recover = false;
			return val9;
		}).ToArray();
		recipes.Add(val7);
	}

	private static void Tint(GameObject go, Color colour)
	{
		//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_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			Material[] sharedMaterials = val.sharedMaterials;
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				if (Object.op_Implicit((Object)(object)sharedMaterials[j]))
				{
					sharedMaterials[j] = new Material(sharedMaterials[j]);
					if (sharedMaterials[j].HasProperty("_Color"))
					{
						sharedMaterials[j].SetColor("_Color", colour);
					}
				}
			}
			val.sharedMaterials = sharedMaterials;
		}
		ParticleSystem[] componentsInChildren2 = go.GetComponentsInChildren<ParticleSystem>(true);
		foreach (ParticleSystem val2 in componentsInChildren2)
		{
			MainModule main = val2.main;
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(colour);
		}
	}

	internal void Register(ObjectDB db)
	{
		try
		{
			Build(db);
			if (!built)
			{
				return;
			}
			foreach (GameObject item in prefabs.Where((GameObject p) => Object.op_Implicit((Object)(object)p.GetComponent<ItemDrop>())))
			{
				if (!db.m_items.Contains(item))
				{
					db.m_items.Add(item);
				}
			}
			foreach (Recipe recipe in recipes)
			{
				if (!db.m_recipes.Contains(recipe))
				{
					db.m_recipes.Add(recipe);
				}
			}
			if (!db.m_StatusEffects.Contains((StatusEffect)(object)leech))
			{
				db.m_StatusEffects.Add((StatusEffect)(object)leech);
			}
		}
		catch (Exception ex)
		{
			failed = true;
			foreach (GameObject prefab in prefabs)
			{
				Object.Destroy((Object)(object)prefab);
			}
			prefabs.Clear();
			foreach (Recipe recipe2 in recipes)
			{
				Object.Destroy((Object)(object)recipe2);
			}
			recipes.Clear();
			if (Object.op_Implicit((Object)(object)leech))
			{
				Object.Destroy((Object)(object)leech);
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Registration failed; no new recipes will be exposed: " + ex));
		}
	}

	private void SyncNetwork(ZNetScene scene)
	{
		//IL_0232: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Expected O, but got Unknown
		if (!built || !Object.op_Implicit((Object)(object)scene))
		{
			return;
		}
		Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene);
		foreach (GameObject prefab in prefabs)
		{
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value != (Object)(object)prefab)
			{
				throw new InvalidOperationException("Network prefab collision: " + ((Object)prefab).name);
			}
			if (!scene.m_prefabs.Contains(prefab))
			{
				scene.m_prefabs.Add(prefab);
			}
			dictionary[stableHashCode] = prefab;
		}
		BombSpec[] all = BombSpec.All;
		foreach (BombSpec spec in all)
		{
			List<GameObject> source = prefabs;
			Func<GameObject, bool> predicate = (GameObject p) => ((Object)p).name == spec.Id + "_Projectile";
			Projectile component = source.First(predicate).GetComponent<Projectile>();
			string[] array = ((spec.Id == "CC_ShatterBomb") ? new string[2] { "fx_crystal_destruction", "sfx_bomblava_rocks" } : ((spec.Id == "CC_FrostFlask") ? new string[2] { "vfx_BombBlob_explode_frost", "sfx_ice_destroyed" } : ((spec.Id == "CC_LeechFlask") ? new string[2] { "vfx_BombBlob_explode_tar", "sfx_oozebomb_explode" } : new string[2] { "vfx_BombBlob_explode_poison", "sfx_oozebomb_explode" })));
			EffectData[] array2 = (from p in ((IEnumerable<string>)array).Select((Func<string, GameObject>)scene.GetPrefab)
				where Object.op_Implicit((Object)(object)p)
				select p).Select(delegate(GameObject p)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Expected O, but got Unknown
				EffectData val2 = new EffectData();
				val2.m_prefab = p;
				val2.m_enabled = true;
				val2.m_variant = -1;
				return val2;
			}).ToArray();
			if (array2.Length == array.Length)
			{
				EffectList val = new EffectList();
				val.m_effectPrefabs = array2;
				component.m_hitEffects = val;
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Some native impact effects unavailable for " + spec.Name + "; retaining native bomb audio fallback."));
			}
		}
	}
}
public sealed class ChemistryBlast : MonoBehaviour
{
}