using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Fartheim")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Fartheim")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("2483fa13-8406-413c-8bad-a5bf7982d98d")]
[assembly: AssemblyFileVersion("1.2.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.1.0")]
[module: UnverifiableCode]
namespace Fartheim;
public class RecipeStub
{
public class RequirementStub
{
public string Component;
public int Amount;
public int AmountPerLevel;
public bool Recoverable = true;
private RequirementStub()
{
}
public static RequirementStub Parse(string def)
{
string[] array = def.Split(new char[1] { ':' });
if (array.Length < 2)
{
return null;
}
RequirementStub requirementStub = new RequirementStub();
requirementStub.Component = array[0];
int.TryParse(array[1], out requirementStub.Amount);
if (array.Length > 2)
{
int.TryParse(array[2], out requirementStub.AmountPerLevel);
}
return requirementStub;
}
}
public ItemDrop Item;
public string CraftingStation;
public string RepairStation;
public int MinStationLevel = 1;
public List<RequirementStub> Requirements = new List<RequirementStub>();
public string Name => "Recipe" + ((Object)Item).name;
}
[HarmonyPatch]
public static class AssetHelper
{
public static readonly List<GameObject> Prefabs = new List<GameObject>();
private static readonly List<RecipeStub> RecipeStubs = new List<RecipeStub>();
private static readonly List<KeyValuePair<string, StatusEffect>> StatusEffects = new List<KeyValuePair<string, StatusEffect>>();
public static AssetBundle LoadAssetBundle(string name)
{
Assembly callingAssembly = Assembly.GetCallingAssembly();
return AssetBundle.LoadFromStream(callingAssembly.GetManifestResourceStream(callingAssembly.GetName().Name + "." + name));
}
public static void RegisterPrefab(GameObject prefab)
{
Prefabs.Add(prefab);
Object.DontDestroyOnLoad((Object)(object)prefab);
}
public static void RegisterRecipe(RecipeStub rs)
{
RecipeStubs.Add(rs);
}
public static void RegisterStatusEffect<T>(string name) where T : StatusEffect
{
StatusEffects.Add(new KeyValuePair<string, StatusEffect>(name, (StatusEffect)(object)ScriptableObject.CreateInstance<T>()));
}
public static RecipeStub GetRecipeStub(string itemName)
{
return RecipeStubs.Find((RecipeStub r) => ((Object)r.Item).name == itemName);
}
public static Recipe BuildRecipe(RecipeStub rs, ObjectDB odb)
{
//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
//IL_01d0: Expected O, but got Unknown
Recipe val = ScriptableObject.CreateInstance<Recipe>();
val.m_item = rs.Item;
GameObject itemPrefab = odb.GetItemPrefab(rs.CraftingStation);
val.m_craftingStation = ((itemPrefab != null) ? itemPrefab.GetComponentInChildren<CraftingStation>(true) : null);
if ((Object)(object)val.m_craftingStation == (Object)null)
{
ZNetScene instance = ZNetScene.instance;
object craftingStation;
if (instance == null)
{
craftingStation = null;
}
else
{
GameObject prefab = instance.GetPrefab(rs.CraftingStation);
craftingStation = ((prefab != null) ? prefab.GetComponentInChildren<CraftingStation>(true) : null);
}
val.m_craftingStation = (CraftingStation)craftingStation;
if ((Object)(object)val.m_craftingStation == (Object)null)
{
Plugin.Log.LogInfo((object)("BuildRecipe couldn't find crafting station " + rs.CraftingStation + " for " + rs.Name));
return null;
}
}
if (!string.IsNullOrWhiteSpace(rs.RepairStation))
{
GameObject itemPrefab2 = odb.GetItemPrefab(rs.RepairStation);
val.m_repairStation = ((itemPrefab2 != null) ? itemPrefab2.GetComponentInChildren<CraftingStation>(true) : null);
if ((Object)(object)val.m_repairStation == (Object)null)
{
ZNetScene instance2 = ZNetScene.instance;
object repairStation;
if (instance2 == null)
{
repairStation = null;
}
else
{
GameObject prefab2 = instance2.GetPrefab(rs.RepairStation);
repairStation = ((prefab2 != null) ? prefab2.GetComponentInChildren<CraftingStation>(true) : null);
}
val.m_repairStation = (CraftingStation)repairStation;
if ((Object)(object)val.m_repairStation == (Object)null)
{
Plugin.Log.LogInfo((object)("BuildRecipe couldn't find declared repair station " + rs.RepairStation + " for " + rs.Name));
return null;
}
}
if ((Object)(object)val.m_repairStation == (Object)null)
{
return null;
}
}
val.m_minStationLevel = Mathf.Max(1, rs.MinStationLevel);
List<Requirement> list = new List<Requirement>();
foreach (RecipeStub.RequirementStub requirement in rs.Requirements)
{
GameObject itemPrefab3 = odb.GetItemPrefab(requirement.Component);
ItemDrop val2 = ((itemPrefab3 != null) ? itemPrefab3.GetComponentInChildren<ItemDrop>(true) : null);
if (!Object.op_Implicit((Object)(object)val2))
{
Plugin.Log.LogInfo((object)("BuildRecipe couldn't get requirement component " + requirement.Component + " for " + rs.Name));
return null;
}
Requirement val3 = new Requirement();
val3.m_resItem = val2;
val3.m_amount = requirement.Amount;
val3.m_amountPerLevel = requirement.AmountPerLevel;
val3.m_recover = requirement.Recoverable;
list.Add(val3);
}
val.m_resources = list.ToArray();
return val;
}
private static void PopulateObjectDB(ObjectDB odb)
{
if (Prefabs.Count > 0 && !Object.op_Implicit((Object)(object)odb.m_items.Find((GameObject p) => ((Object)p).name == ((Object)Prefabs[0]).name)))
{
foreach (GameObject prefab in Prefabs)
{
if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ItemDrop>(true)))
{
odb.m_items.Add(prefab);
}
}
odb.UpdateRegisters();
}
if (RecipeStubs.Count > 0 && !Object.op_Implicit((Object)(object)odb.GetRecipe(RecipeStubs[0].Item.m_itemData)))
{
foreach (RecipeStub recipeStub in RecipeStubs)
{
Recipe val = BuildRecipe(recipeStub, odb);
if (Object.op_Implicit((Object)(object)val))
{
odb.m_recipes.Add(val);
Plugin.Log.LogInfo((object)("Added recipe " + ((Object)val).name));
}
}
}
if (StatusEffects.Count <= 0 || Object.op_Implicit((Object)(object)odb.GetStatusEffect(StringExtensionMethods.GetStableHashCode(StatusEffects[0].Key))))
{
return;
}
foreach (KeyValuePair<string, StatusEffect> statusEffect in StatusEffects)
{
odb.m_StatusEffects.Add(statusEffect.Value);
}
}
public static void UpdateRecipes()
{
foreach (RecipeStub recipeStub in RecipeStubs)
{
Recipe r = BuildRecipe(recipeStub, ObjectDB.instance);
if (Object.op_Implicit((Object)(object)r))
{
Recipe val = ObjectDB.instance.m_recipes.Find((Recipe rt) => ((Object)rt).name == ((Object)r).name);
if (Object.op_Implicit((Object)(object)val))
{
ObjectDB.instance.m_recipes.Remove(val);
}
ObjectDB.instance.m_recipes.Add(r);
Plugin.Log.LogInfo((object)("Updated recipe " + ((Object)r).name));
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ObjectDB), "Awake")]
public static void AwakePostfix(ObjectDB __instance)
{
PopulateObjectDB(__instance);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
public static void CopyOtherDBPostfix(ObjectDB __instance, ObjectDB other)
{
PopulateObjectDB(__instance);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ZNetScene), "Awake")]
public static void AwakePostfix(ZNetScene __instance)
{
if (Prefabs.Count == 0)
{
return;
}
foreach (GameObject prefab in Prefabs)
{
__instance.m_namedPrefabs[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab;
}
}
}
public class Farter : MonoBehaviour
{
private static string[] BoneRoots = new string[3] { "Hip", "Hips", "l_hip" };
private AudioSource AS;
private Character Char;
private bool Crouching;
private float TimeSinceLastFart;
private float FartTimerDelay;
private ParticleSystem PS;
private float SizeScalar = 1f;
public void Awake()
{
//IL_0381: Unknown result type (might be due to invalid IL or missing references)
//IL_0386: Unknown result type (might be due to invalid IL or missing references)
//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
Char = ((Component)this).GetComponentInChildren<Character>();
AS = ((Component)this).gameObject.AddComponent<AudioSource>();
AS.playOnAwake = false;
AS.maxDistance = Plugin.FartNoiseRange.Value;
AS.rolloffMode = (AudioRolloffMode)1;
AS.spatialBlend = 1f;
AS.outputAudioMixerGroup = AudioMan.m_instance.m_ambientMixer;
Transform val = null;
if (Object.op_Implicit((Object)(object)Char) && !((Object)((Component)this).gameObject).name.StartsWith("Skeleton") && !((Object)((Component)this).gameObject).name.StartsWith("Blob"))
{
string bone = null;
SkinnedMeshRenderer componentInChildren = ((Component)this).gameObject.GetComponentInChildren<SkinnedMeshRenderer>();
if (Object.op_Implicit((Object)(object)componentInChildren))
{
if (((Object)((Component)this).gameObject).name.StartsWith("Boar") || ((Object)((Component)this).gameObject).name.StartsWith("Wolf"))
{
bone = "Pelvis";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Deer"))
{
bone = "L Thigh";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Dragon"))
{
bone = "Hips.001";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Draugr"))
{
bone = "LeftHip";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Eikthyr"))
{
bone = "Bone.009";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Hatchling"))
{
bone = "Spine1";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Surtling"))
{
bone = "mixamorig:Hips";
}
else if (((Object)((Component)this).gameObject).name.StartsWith("Troll"))
{
bone = "Spine0";
}
if (bone != null)
{
val = ((IEnumerable<Transform>)componentInChildren.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == bone));
if (!Object.op_Implicit((Object)(object)val))
{
val = ((Component)this).transform;
}
}
else
{
val = ((IEnumerable<Transform>)componentInChildren.bones).FirstOrDefault((Func<Transform, bool>)((Transform t) => BoneRoots.Contains(((Object)t).name)));
}
}
}
if (!Object.op_Implicit((Object)(object)val))
{
val = ((Component)this).transform;
}
GameObject val2 = Object.Instantiate<GameObject>(Plugin.FartSystemPrefab, val);
PS = val2.GetComponent<ParticleSystem>();
CapsuleCollider componentInChildren2 = ((Component)this).gameObject.GetComponentInChildren<CapsuleCollider>();
if (Object.op_Implicit((Object)(object)componentInChildren2))
{
double num = componentInChildren2.radius;
double num2 = componentInChildren2.height;
double num3 = 4.1887902047863905 * Math.Pow(num, 3.0);
if (num2 - 2.0 * num > 0.0)
{
num3 += Math.PI * Math.Pow(num, 2.0);
}
SizeScalar = (float)Math.Sqrt(num3);
}
else
{
SphereCollider componentInChildren3 = ((Component)this).gameObject.GetComponentInChildren<SphereCollider>();
if (Object.op_Implicit((Object)(object)componentInChildren3))
{
double d = 4.1887902047863905 * Math.Pow(componentInChildren3.radius, 3.0);
SizeScalar = (float)Math.Sqrt(d);
}
}
if (SizeScalar != 1f)
{
MainModule main = PS.main;
((MainModule)(ref main)).startSpeedMultiplier = SizeScalar;
((MainModule)(ref main)).startSizeMultiplier = SizeScalar;
VelocityOverLifetimeModule velocityOverLifetime = PS.velocityOverLifetime;
((VelocityOverLifetimeModule)(ref velocityOverLifetime)).speedModifierMultiplier = SizeScalar;
}
}
private void Fart()
{
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: 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)
List<AudioClip> list = ((Object.op_Implicit((Object)(object)Char) && Char.InWater()) ? Plugin.WetFarts : Plugin.DryFarts);
int index = ((!Object.op_Implicit((Object)(object)Char) || !Char.IsPlayer() || !Plugin.BunsOfSteel.Value) ? Mathf.Min(list.Count - 1, (int)(Random.value * (float)list.Count)) : Mathf.Min(list.Count - 1, (int)(TimeSinceLastFart / Plugin.MaxFartTime.Value * (float)list.Count)));
AudioClip val = list[index];
AS.pitch = (0.75f + Random.value * 0.5f) / SizeScalar;
AS.PlayOneShot(val, Mathf.Clamp(TimeSinceLastFart / Plugin.MaxFartTime.Value, 0.25f, 1f));
FartTimerDelay = val.length + 1f + Random.value;
TimeSinceLastFart = 0f;
((Component)PS).transform.rotation = Quaternion.LookRotation(-((Component)this).transform.forward, ((Component)this).transform.up);
MainModule main = PS.main;
((MainModule)(ref main)).duration = val.length;
PS.Play();
}
public void Update()
{
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
{
return;
}
if (!Object.op_Implicit((Object)(object)Char) || !Char.IsPlayer() || !Plugin.BunsOfSteel.Value)
{
if (FartTimerDelay <= 0f)
{
TimeSinceLastFart += Time.deltaTime;
float num = Random.value * Plugin.MaxFartTime.Value;
if (TimeSinceLastFart >= num)
{
Fart();
}
else
{
FartTimerDelay += 0.5f + Random.value;
}
}
else
{
FartTimerDelay -= Time.deltaTime;
if (TimeSinceLastFart > 0f)
{
TimeSinceLastFart += Time.deltaTime;
}
}
}
else
{
TimeSinceLastFart += Time.deltaTime;
}
if (Object.op_Implicit((Object)(object)Char) && Char.IsCrouching())
{
if (!Crouching)
{
Crouching = true;
Fart();
}
}
else if (Crouching)
{
Crouching = false;
}
if (Object.op_Implicit((Object)(object)PS))
{
ForceOverLifetimeModule forceOverLifetime = PS.forceOverLifetime;
if (Object.op_Implicit((Object)(object)Char) && (Char.InInterior() || (Char.IsPlayer() && ((Player)/*isinst with value type is only supported in some contexts*/).InShelter())))
{
((ForceOverLifetimeModule)(ref forceOverLifetime)).x = MinMaxCurve.op_Implicit(0f);
((ForceOverLifetimeModule)(ref forceOverLifetime)).z = MinMaxCurve.op_Implicit(0f);
}
else
{
Vector3 windForce = EnvMan.instance.GetWindForce();
((ForceOverLifetimeModule)(ref forceOverLifetime)).x = MinMaxCurve.op_Implicit(windForce.x * 3f);
((ForceOverLifetimeModule)(ref forceOverLifetime)).z = MinMaxCurve.op_Implicit(windForce.z * 3f);
}
}
}
}
[HarmonyPatch(typeof(Character))]
public class CharacterPatches
{
[HarmonyPostfix]
[HarmonyPatch("Awake")]
public static void AwakePostfix(Character __instance)
{
if (!Plugin.OnlyPlayers.Value || __instance is Player)
{
((Component)__instance).gameObject.AddComponent<Farter>();
}
}
}
[HarmonyPatch(typeof(RandomFlyingBird))]
public class RandomFlyingBirdPatches
{
[HarmonyPostfix]
[HarmonyPatch("Awake")]
public static void AwakePostfix(RandomFlyingBird __instance)
{
if (Plugin.ShouldBirdsFart.Value)
{
((Component)__instance).gameObject.AddComponent<Farter>();
}
}
}
[BepInPlugin("pfhoenix.fartheim", "Fartheim", "1.2.1")]
public class Plugin : BaseUnityPlugin
{
public const string Version = "1.2.1";
public const string ModName = "Fartheim";
private Harmony _Harmony;
public static ManualLogSource Log;
private AssetBundle AB;
public static List<AudioClip> DryFarts = new List<AudioClip>();
public static List<AudioClip> WetFarts = new List<AudioClip>();
public static GameObject FartSystemPrefab;
public static ConfigEntry<float> MaxFartTime;
public static ConfigEntry<float> FartNoiseRange;
public static ConfigEntry<bool> BunsOfSteel;
public static ConfigEntry<bool> ShouldBirdsFart;
public static ConfigEntry<bool> OnlyPlayers;
private void Awake()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
Log = new ManualLogSource((string)null);
AB = AssetHelper.LoadAssetBundle("fartheim");
AudioClip[] array = AB.LoadAllAssets<AudioClip>();
foreach (AudioClip val in array)
{
if (((Object)val).name.Contains("water"))
{
WetFarts.Add(val);
}
else
{
DryFarts.Add(val);
}
}
if (DryFarts.Count > 0)
{
DryFarts = DryFarts.OrderBy((AudioClip f) => f.length).ToList();
}
if (WetFarts.Count > 0)
{
WetFarts = WetFarts.OrderBy((AudioClip f) => f.length).ToList();
}
FartSystemPrefab = AB.LoadAsset<GameObject>("Assets\\FartSystem.prefab");
AssetHelper.RegisterPrefab(FartSystemPrefab);
MaxFartTime = ((BaseUnityPlugin)this).Config.Bind<float>("Farts", "Maximum Fart Time", 30f, (ConfigDescription)null);
FartNoiseRange = ((BaseUnityPlugin)this).Config.Bind<float>("Farts", "Fart Noise Range", 32f, (ConfigDescription)null);
BunsOfSteel = ((BaseUnityPlugin)this).Config.Bind<bool>("Farts", "Players Only Fart When Crouching", true, (ConfigDescription)null);
ShouldBirdsFart = ((BaseUnityPlugin)this).Config.Bind<bool>("Farts", "Should Birds Fart", true, (ConfigDescription)null);
OnlyPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Farts", "Only Players Fart (unrealistic)", false, (ConfigDescription)null);
_Harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
}
private void OnDestroy()
{
if (_Harmony != null)
{
_Harmony.UnpatchSelf();
}
}
}