Decompiled source of Bogus Valheim v1.0.17

plugins/BogusFreeBossSummons.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
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: AssemblyVersion("0.0.0.0")]
namespace BogusFreeBossSummons;

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("bogus.freebosssummons", "Bogus Free Boss Summons", "1.3.1")]
public class Plugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(OfferingBowl), "Interact")]
	private static class BowlInteract
	{
		private static bool Prefix(OfferingBowl __instance, Humanoid user, bool hold, ref bool __result)
		{
			if (!IsFree(__instance))
			{
				return true;
			}
			__result = false;
			if (hold)
			{
				return false;
			}
			if ((bool)miQueued.Invoke(__instance, null))
			{
				return false;
			}
			fiUser.SetValue(__instance, user);
			object obj = miSpawnPos.Invoke(__instance, null);
			miInitiate.Invoke(__instance, new object[2] { obj, false });
			__result = true;
			return false;
		}
	}

	[HarmonyPatch(typeof(OfferingBowl), "GetHoverText")]
	private static class BowlHover
	{
		private static void Postfix(OfferingBowl __instance, ref string __result)
		{
			if (IsFree(__instance))
			{
				int num = ((__result == null) ? (-1) : __result.IndexOf('\n'));
				string text = ((num > 0) ? __result.Substring(0, num) : (__result ?? ""));
				__result = text + "\n[<color=yellow><b>E</b></color>] Summon (free)";
			}
		}
	}

	[HarmonyPatch(typeof(Tameable), "Awake")]
	private static class SummonAwake
	{
		private static void Postfix(Tameable __instance)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (!SummonXP.Value || (!(__instance.m_unsummonDistance > 0f) && !(__instance.m_unsummonOnOwnerLogoutSeconds > 0f)))
			{
				return;
			}
			string text = Clean(((Object)((Component)__instance).gameObject).name);
			if ((int)__instance.m_levelUpOwnerSkill == 0)
			{
				__instance.m_levelUpOwnerSkill = (SkillType)10;
				__instance.m_levelUpFactor = SummonXPFactor.Value;
				if (summonLogged.Add(text))
				{
					Log.LogInfo((object)("Summon " + text + " now gives its owner Blood Magic XP x" + SummonXPFactor.Value));
				}
			}
			else if (summonLogged.Add(text))
			{
				Log.LogInfo((object)("Summon " + text + " already gives owner XP in " + ((object)Unsafe.As<SkillType, SkillType>(ref __instance.m_levelUpOwnerSkill)/*cast due to .constrained prefix*/).ToString() + " x" + __instance.m_levelUpFactor));
			}
		}
	}

	[HarmonyPatch(typeof(Door), "HaveKey")]
	private static class DoorKey
	{
		private static bool Prefix(Door __instance, ref bool __result)
		{
			if (Object.op_Implicit((Object)(object)__instance.m_keyItem) && InList(FreeDoorKeys.Value, Clean(((Object)__instance.m_keyItem).name)))
			{
				__result = true;
				return false;
			}
			return true;
		}
	}

	internal static ConfigEntry<string> FreeBosses;

	internal static ConfigEntry<string> FreeDoorKeys;

	internal static ConfigEntry<string> NoLootChestBosses;

	internal static ConfigEntry<bool> SummonXP;

	internal static ConfigEntry<float> SummonXPFactor;

	internal static ManualLogSource Log;

	private static Harmony _harmony;

	private static readonly HashSet<string> logged = new HashSet<string>();

	private static readonly MethodInfo miQueued = AccessTools.Method(typeof(OfferingBowl), "IsBossSpawnQueued", (Type[])null, (Type[])null);

	private static readonly MethodInfo miSpawnPos = AccessTools.Method(typeof(OfferingBowl), "GetSpawnPosition", (Type[])null, (Type[])null);

	private static readonly MethodInfo miInitiate = AccessTools.Method(typeof(OfferingBowl), "InitiateSpawnBoss", (Type[])null, (Type[])null);

	private static readonly FieldInfo fiUser = AccessTools.Field(typeof(OfferingBowl), "m_interactUser");

	private static readonly HashSet<string> summonLogged = new HashSet<string>();

	private void Awake()
	{
		//IL_00c0: 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_00d0: Expected O, but got Unknown
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Expected O, but got Unknown
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		FreeBosses = ((BaseUnityPlugin)this).Config.Bind<string>("General", "FreeBosses", "Eikthyr,gd_king,Bonemass,Dragon,GoblinKing,SeekerQueen,Fader", "Boss prefab names whose altar summons for free (no offering). Bosses not listed keep their vanilla cost.");
		FreeDoorKeys = ((BaseUnityPlugin)this).Config.Bind<string>("General", "FreeDoorKeys", "DvergrKey", "Key item prefab names that are no longer needed to open their door (DvergrKey = Sealbreaker, the Queen's sealed tower).");
		NoLootChestBosses = ((BaseUnityPlugin)this).Config.Bind<string>("General", "NoLootChestBosses", "SeekerQueen", "Boss prefab names whose loot drops normally instead of going into a BossLootChests chest (the Queen's sky arena makes the chest fall to the ground below).");
		SummonXP = ((BaseUnityPlugin)this).Config.Bind<bool>("SummonXP", "Enabled", true, "Summoned creatures (Spirit Caller, Dead Raiser, Trollstav...) give the player they follow Blood Magic XP every time they hit something.");
		SummonXPFactor = ((BaseUnityPlugin)this).Config.Bind<float>("SummonXP", "XPFactor", 1f, "Blood Magic XP per summon hit, relative to the XP a player weapon hit gives. 1 = same as your own hit, 0.5 = half.");
		Harmony val = new Harmony("bogus.freebosssummons");
		val.PatchAll();
		_harmony = val;
		new ConsoleCommand("bogus_pullloot", "[radius] [pull] Lists containers with items nearby (any height). 'pull' drops boss loot chest contents at your feet.", new ConsoleEvent(PullLoot), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		Log.LogInfo((object)("Bogus Free Boss Summons loaded. Free bosses: " + FreeBosses.Value + " | Free door keys: " + FreeDoorKeys.Value));
	}

	private void Start()
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		Harmony harmony = _harmony;
		try
		{
			Type type = AccessTools.TypeByName("Cjayride.BossLootChests.BountyTargets");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "SkipChestCapture", (Type[])null, (Type[])null));
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "SkipChestPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("BossLootChests hooked. No loot chest for: " + NoLootChestBosses.Value));
			}
			else
			{
				Log.LogInfo((object)"BossLootChests not found; loot chest skip not active.");
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not hook BossLootChests: " + ex.Message));
		}
	}

	private static void PullLoot(ConsoleEventArgs args)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			args.Context.AddString("No player.");
			return;
		}
		bool flag = false;
		float num = 300f;
		for (int i = 1; i < args.Length; i++)
		{
			float result;
			if (args[i].ToLower() == "pull")
			{
				flag = true;
			}
			else if (float.TryParse(args[i], out result))
			{
				num = result;
			}
		}
		Vector3 position = ((Component)localPlayer).transform.position;
		int num2 = 0;
		int num3 = 0;
		Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
		foreach (Container val in array)
		{
			Vector3 position2 = ((Component)val).transform.position;
			Vector2 val2 = new Vector2(position2.x - position.x, position2.z - position.z);
			float magnitude = ((Vector2)(ref val2)).magnitude;
			if (magnitude > num)
			{
				continue;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				continue;
			}
			Inventory inventory = val.GetInventory();
			if (inventory == null)
			{
				continue;
			}
			List<ItemData> list = new List<ItemData>(inventory.GetAllItems());
			Piece component2 = ((Component)val).GetComponent<Piece>();
			long num4 = (Object.op_Implicit((Object)(object)component2) ? component2.GetCreator() : 0);
			bool flag2 = ((Object)val).name.StartsWith("piece_chest_blackmetal") && num4 == 0;
			if (list.Count == 0 && !flag2)
			{
				continue;
			}
			num2++;
			args.Context.AddString(string.Format("#{0} {1}: {2:0} m away sideways, height {3:0} (you {4:0}), {5} stacks{6}", num2, Clean(((Object)val).name), magnitude, position2.y, position.y, list.Count, flag2 ? " <- boss loot chest" : ((num4 != 0L) ? " (player-built)" : "")));
			if (!flag || !flag2 || list.Count == 0)
			{
				continue;
			}
			component.ClaimOwnership();
			foreach (ItemData item in list)
			{
				ItemDrop.DropItem(item, item.m_stack, position + Vector3.up + ((Component)localPlayer).transform.forward, Quaternion.identity);
				inventory.RemoveItem(item);
				num3++;
			}
		}
		if (num2 == 0)
		{
			args.Context.AddString("No containers with items within " + num + " m.");
		}
		else if (flag)
		{
			args.Context.AddString("Dropped " + num3 + " stacks from boss loot chests at your feet.");
		}
		else
		{
			args.Context.AddString("Run 'bogus_pullloot pull' (optionally with a radius, e.g. 'bogus_pullloot 500 pull') to drop boss loot chest contents at your feet.");
		}
	}

	private static void SkipChestPostfix(Character character, ref bool __result)
	{
		if (!__result && Object.op_Implicit((Object)(object)character) && InList(NoLootChestBosses.Value, Clean(((Object)((Component)character).gameObject).name)))
		{
			__result = true;
		}
	}

	internal static bool InList(string csv, string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		string[] array = csv.Split(',');
		for (int i = 0; i < array.Length; i++)
		{
			if (string.Equals(array[i].Trim(), name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}

	internal static string Clean(string n)
	{
		if (n != null)
		{
			return n.Replace("(Clone)", "").Trim();
		}
		return "";
	}

	internal static bool IsFree(OfferingBowl bowl)
	{
		string text = (Object.op_Implicit((Object)(object)bowl.m_bossPrefab) ? Clean(((Object)bowl.m_bossPrefab).name) : "");
		string text2 = (Object.op_Implicit((Object)(object)bowl.m_bossItem) ? Clean(((Object)bowl.m_bossItem).name) : "");
		string item = text + "|" + text2;
		bool result = text != "" && InList(FreeBosses.Value, text);
		if (logged.Add(item))
		{
			Log.LogInfo((object)("Altar boss=" + text + " offering=" + text2 + "x" + bowl.m_bossItems + " itemStands=" + bowl.m_useItemStands + " free=" + result));
		}
		return result;
	}
}