using System;
using System.Collections;
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.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Zen;
using Zen.Lib;
using Zen.Lib.Config;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenBossStone")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZenBossStone")]
[assembly: AssemblyCopyright("Copyright \ufffd 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 ZenBossStone
{
public static class Commands
{
public static void RegisterRPC()
{
ZRoutedRpc.instance.Register<string>("RPC_BossStoneReset", (Action<long, string>)RPC_BossStoneReset);
ZRoutedRpc.instance.Register<string>("RPC_BossStoneResponse", (Action<long, string>)RPC_BossStoneResponse);
}
public static void Init()
{
ZenMod<Plugin>.Terminal.CreateCommand("Reset", "Remove all trophies from ZDO data on Boss Stones and all player private keys for stones. Must be standing near them for it to work.", true, (Action<string[]>)delegate(string[] args)
{
if (args.Length <= 1)
{
Console.instance.Print("Syntax: " + args[0] + " playerName");
}
else
{
string text = args[1];
ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RPC_BossStoneReset", new object[1] { text });
}
});
}
private static void RPC_BossStoneReset(long sender, string playerName)
{
if (!string.Equals(playerName, Player.m_localPlayer.GetPlayerName(), StringComparison.CurrentCultureIgnoreCase))
{
return;
}
Logging<Plugin>.Warning((object)$"Reset boss stones command sent from {sender} to {playerName}", 0);
StringBuilder stringBuilder = new StringBuilder();
BossStone[] array = Object.FindObjectsByType<BossStone>((FindObjectsSortMode)0);
Player localPlayer = Player.m_localPlayer;
stringBuilder.AppendLine(string.Format("{0} count: {1}", "BossStone", array.Length));
if (((Character)localPlayer).InGodMode())
{
BossStone[] array2 = array;
foreach (BossStone val in array2)
{
val.m_activeEffect.SetActive(false);
ZNetView nview = val.m_itemStand.m_nview;
nview.ClaimOwnership();
nview.GetZDO().Set(ZDOVars.s_item, string.Empty);
stringBuilder.AppendLine("Global ZDO Reset: " + Utils.GetPrefabName(((Object)val).name));
}
}
else
{
stringBuilder.AppendLine("BossStone ZDO data not reset, " + playerName + " is not in God mode.");
}
stringBuilder.AppendLine("Remove private player keys");
ItemStand[] array3 = Resources.FindObjectsOfTypeAll<ItemStand>();
foreach (ItemStand val2 in array3)
{
if (Object.op_Implicit((Object)(object)val2.m_guardianPower))
{
string name = ((Object)val2.m_guardianPower).name;
((Humanoid)localPlayer).RemoveUniqueKey(name);
stringBuilder.AppendLine("Removed: " + name);
}
}
stringBuilder.AppendLine("Player guardian power reset");
PlayerExt.RemoveGuardianPower(localPlayer);
ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RPC_BossStoneResponse", new object[1] { stringBuilder.ToString() });
}
private static void RPC_BossStoneResponse(long sender, string message)
{
Console.instance.Print(message);
}
public static void UnregisterRPC()
{
ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_BossStoneReset");
ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_BossStoneResponse");
}
}
[HarmonyPatch]
internal static class PatchBossStone
{
[HarmonyPatch(typeof(BossStone), "DelayedAttachEffects_Step3")]
private static class BossStone_DelayedAttachEffects_Step3
{
[UsedImplicitly]
private static void Prefix(BossStone __instance)
{
ZNetView.m_forceDisableInit = true;
}
[UsedImplicitly]
private static void Postfix(BossStone __instance)
{
ZNetView.m_forceDisableInit = false;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BossStone), "Start")]
private static void BossStone_Start(BossStone __instance)
{
if (Configs.SacrificeTrophyForBossLoot.Value)
{
SetupFX(__instance);
}
}
private static void SetupFX(BossStone bossStone)
{
EffectList val = bossStone.GetBoss().m_deathEffects;
EffectData[] effectPrefabs = val.m_effectPrefabs;
Ragdoll val2 = default(Ragdoll);
for (int i = 0; i < effectPrefabs.Length; i++)
{
if (effectPrefabs[i].m_prefab.TryGetComponent<Ragdoll>(ref val2))
{
val = val2.m_removeEffect;
break;
}
}
bossStone.m_activateStep3.m_effectPrefabs = CollectionExtensions.AddRangeToArray<EffectData>(bossStone.m_activateStep3.m_effectPrefabs, val.m_effectPrefabs);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(BossStone), "SetActivated")]
private static void BossStone_SetActivated(BossStone __instance, ref bool triggerEffect)
{
triggerEffect = State.IsInvokingSacrifice;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BossStone), "DelayedAttachEffects_Step3")]
private static IEnumerable<CodeInstruction> BossStone_DelayedAttachEffects_Step3_Transpile(IEnumerable<CodeInstruction> codes)
{
MethodInfo methodInfo = AccessTools.Method(typeof(Player), "MessageAllInRange", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(PatchBossStone), "MessageAllInRange_Intercept", (Type[])null, (Type[])null);
return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)methodInfo2);
}
private static void MessageAllInRange_Intercept(Vector3 point, float range, MessageType type, string msg, Sprite? icon = null)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
if (Configs.PerPlayerBossStones.Value)
{
((Character)Player.m_localPlayer).Message(type, msg, 0, (Sprite)null);
}
else
{
Player.MessageAllInRange(point, range, type, msg, icon);
}
}
}
internal static class Configs
{
public static readonly ConfigEntry<bool> AutoSetWorldModifierPlayerEvents;
public static readonly ConfigEntry<bool> PerPlayerBossStones;
public static readonly ConfigEntry<bool> SacrificeTrophyForBossLoot;
public static readonly ConfigEntry<bool> RemoveTrophyFromRaidReqs;
public static readonly ConfigEntry<PowerEmotes> EmoteToReceivePower;
public static readonly ConfigEntry<bool> BossTrophyOnePerPlayer;
private static readonly ConfigEntry<float> BossTrophyWeight;
private static readonly ConfigEntry<int> BossTrophyMaxStackSize;
private static readonly ConfigEntry<bool> BossTrophyAutoPickup;
private static readonly ConfigEntry<bool> BossTrophyNoTeleport;
internal static readonly Dictionary<string, string> TrophyToBoss;
internal const float LootSpawnDelay = 12f;
static Configs()
{
TrophyToBoss = new Dictionary<string, string>();
AutoSetWorldModifierPlayerEvents = Config.Define<bool>(true, "General", "Autoset World Modifier PlayerEvents", true, "Automatically enable the world modifier PlayerEvents on startup. (If run on server)\nThis will enable Valheim's player based progression.\nIf you are unfamiliar with how this modifier works please read the wiki:\nhttps://valheim.fandom.com/wiki/Events#Player-based_requirements");
PerPlayerBossStones = Config.Define<bool>(true, "General", "Per Player Boss Stones", true, "Each player sees their own version of reality.\nAny player standing in the Start Temple when a trophy is sacrificed will have the trophy hung\nin their reality as well. Any player not standing in the Start Temple when a trophy is sacrificed will\nnot see the trophy in their reality.");
SacrificeTrophyForBossLoot = Config.Define<bool>(true, "General", "Sacrifice Trophy For Boss Loot", true, "Sacrifice boss trophy at boss stones for boss loot instead of dropping the loot directly from the boss when they die.\nCan sacrifice multiple boss trophies for extra loot");
EmoteToReceivePower = Config.Define<PowerEmotes>(false, "General", "Emote To Recieve Power", PowerEmotes.Flex, "Player emotes to recieve guardian power. Just looks cool. Set to None to disable");
BossTrophyWeight = Config.Define<float>(true, "Trophy", "Boss Trophy Weight", 250f, Config.AcceptRange<float>(0f, 500f), "How much do boss trophies weigh? (Vanilla: 2)\r\nThe idea is that a boss trophy is a large heavy object that is no-teleport and uses an entire inventory slot.\r\nThis creates a dynamic adventure of hunting, killing, and returning the trophy to the start.\r\nYou may need to craft a cart, carve paths, and use ships to haul it. The journey is the adventure.");
BossTrophyMaxStackSize = Config.Define<int>(true, "Trophy", "Boss Trophy Max Stack Size", 1, Config.AcceptRange<int>(1, 99), "Max stack size of boss trophies (Vanilla: 20)\r\nThe idea is that a boss trophy is a large heavy object that is no-teleport and uses an entire inventory slot.\r\nThis creates a dynamic adventure of hunting, killing, and returning the trophy to the start.\r\nYou may need to craft a cart, carve paths, and use ships to haul it. The journey is the adventure.");
BossTrophyNoTeleport = Config.Define<bool>(true, "Trophy", "Boss Trophy No Teleport", true, "Boss trophies are no-teleport? (Vanilla: false)\r\nThe idea is that a boss trophy is a large heavy object that is no-teleport and uses an entire inventory slot.\r\nThis creates a dynamic adventure of hunting, killing, and returning the trophy to the start.\r\nYou may need to craft a cart, carve paths, and use ships to haul it. The journey is the adventure.");
RemoveTrophyFromRaidReqs = Config.Define<bool>(true, "Trophy", "Remove Trophy From Raid Requirements", true, "In vanilla when player based raids (PlayerEvents) is enabled it makes it possible to trigger raids by simply picking up the boss trophy.\r\nWhen this option is enabled then knowledge of the boss trophy will be ignored when calculating raid requirements.\r\n(Vanilla: false)");
BossTrophyAutoPickup = Config.Define<bool>(true, "Trophy", "Boss Trophy Autopickup", false, "Autopickup boss trophies? (Vanilla: true)\r\nNote: Vanilla's PlayerEvents uses boss trophy pickup as a way of checking progression.\r\nIf you pickup a trophy by accident you will be flagged for that boss's progression and raids.\r\nHowever, if you enable the config option " + ((ConfigEntryBase)RemoveTrophyFromRaidReqs).Definition.Key + " then the boss trophy will be ignored.");
BossTrophyOnePerPlayer = Config.Define<bool>(true, "Trophy", "Boss Trophy One Per Player", false, "One boss trophy drops per player logged into the server when a boss dies. (Vanilla: false)\r\nIn vanilla some boss loot drops one per player and other drops a flat amount.\r\nEikthyr for example drops 3x antlers. However, The Elder drops 1 swamp key per player.\r\nWith this enabled then when the boss dies they drop one trophy per player, but each trophy\r\nwill only drop 1 copy of it's loot, not one copy of loot per player.\r\nIf this is on:\r\nIf two people kill Eikthyr then you will have two trophies and 6x antlers.\r\nIf two people kill The Elder then you will have two trophies and 2x keys.\r\nIf this is off:\r\nIf two people kill Eikthyr then you will have one trophy and 3x antlers.\r\nIf two people kill The Elder then you will have one trophy and 2x keys.");
}
internal static void Init()
{
BuildTrophyToBossLookup();
SetupBossTrophyPrefabs();
if (RemoveTrophyFromRaidReqs.Value)
{
RemoveBossTrophyFromRaidRequirements();
}
}
private static void BuildTrophyToBossLookup()
{
Logging<Plugin>.Info((object)"Building Trophy To Boss Lookup", 0);
ItemStand[] source = (from stone in Resources.FindObjectsOfTypeAll<BossStone>()
where !((Behaviour)stone).isActiveAndEnabled
select ((Component)stone).GetComponentInChildren<ItemStand>() into stand
where (Object)(object)stand != (Object)null
select stand).ToArray();
IEnumerable<Character> enumerable = from c in Resources.FindObjectsOfTypeAll<Character>()
where c.m_boss && !((Behaviour)c).isActiveAndEnabled
select c;
TrophyToBoss.Clear();
CharacterDrop val = default(CharacterDrop);
foreach (Character item in enumerable)
{
Logging<Plugin>.Info((object)("Processing: " + ((Object)item).name), 0);
if (!((Component)item).TryGetComponent<CharacterDrop>(ref val))
{
Logging<Plugin>.Info((object)(((Object)item).name + " - No loot drops found, skipping"), 0);
continue;
}
ItemDrop trophy = val.m_drops.Select((Drop d) => d.m_prefab.GetComponent<ItemDrop>()).FirstOrDefault((Func<ItemDrop, bool>)((ItemDrop item) => Object.op_Implicit((Object)(object)item) && ItemDataExt.IsItemType(item.m_itemData, (ItemType)13)));
if (!Object.op_Implicit((Object)(object)trophy))
{
Logging<Plugin>.Info((object)("No trophy found for boss: " + ((Object)item).name + ", skipping"), 0);
}
else if (!Object.op_Implicit((Object)(object)((IEnumerable<ItemStand>)source).FirstOrDefault((Func<ItemStand, bool>)((ItemStand stand) => stand.IsSupported(trophy.m_itemData)))))
{
Logging<Plugin>.Info((object)("No BossStone ItemStand found for boss " + ((Object)item).name + " trophy: " + ItemDataExt.GetPrefabName(trophy) + ", skipping"), 0);
}
else
{
TrophyToBoss[((Object)trophy).name] = ((Object)item).name;
}
}
foreach (KeyValuePair<string, string> item2 in TrophyToBoss)
{
Logging<Plugin>.Info((object)(item2.Key + ": " + item2.Value), 0);
}
}
private static void SetupBossTrophyPrefabs()
{
Logging<Plugin>.Info((object)"Setup Boss Trophy Prefabs", 0);
Logging<Plugin>.Info((object)$"Autopickup: {BossTrophyAutoPickup.Value}", 0);
Logging<Plugin>.Info((object)$"NoTeleport: {BossTrophyNoTeleport.Value}", 0);
Logging<Plugin>.Info((object)$"Weight: {BossTrophyWeight.Value}", 0);
Logging<Plugin>.Info((object)$"MaxStackSize: {BossTrophyMaxStackSize.Value}", 0);
GameObject val = default(GameObject);
foreach (string key in TrophyToBoss.Keys)
{
if (!ObjectDB.instance.TryGetItemPrefab(key, ref val))
{
throw new Exception("Trophy missing from ObjectDB: " + key);
}
Logging<Plugin>.Info((object)("- " + key), 0);
ItemDrop component = val.GetComponent<ItemDrop>();
component.m_autoPickup = BossTrophyAutoPickup.Value;
component.m_itemData.m_shared.m_teleportable = !BossTrophyNoTeleport.Value;
component.m_itemData.m_shared.m_weight = BossTrophyWeight.Value;
component.m_itemData.m_shared.m_maxStackSize = BossTrophyMaxStackSize.Value;
}
}
private static void RemoveBossTrophyFromRaidRequirements()
{
foreach (RandomEvent @event in RandEventSystem.instance.m_events)
{
RemoveTrophy(@event.m_name, @event.m_altRequiredKnownItems);
RemoveTrophy(@event.m_name, @event.m_altRequiredNotKnownItems);
}
static void RemoveTrophy(string raidName, List<ItemDrop> list)
{
ItemDrop[] array = list.ToArray();
foreach (ItemDrop val in array)
{
string prefabName = ItemDataExt.GetPrefabName(val);
if (TrophyToBoss.ContainsKey(prefabName))
{
list.Remove(val);
Logging<Plugin>.Info((object)(raidName + ": Removed " + prefabName), 0);
}
}
}
}
}
public static class Extensions
{
[CompilerGenerated]
private sealed class <GetBossLoot>d__10 : IEnumerable<KeyValuePair<GameObject, int>>, IEnumerable, IEnumerator<KeyValuePair<GameObject, int>>, IDisposable, IEnumerator
{
private int <>1__state;
private KeyValuePair<GameObject, int> <>2__current;
private int <>l__initialThreadId;
private CharacterDrop charDrop;
public CharacterDrop <>3__charDrop;
private int <lvlMult>5__2;
private IEnumerator<Drop> <>7__wrap2;
KeyValuePair<GameObject, int> IEnumerator<KeyValuePair<GameObject, int>>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <GetBossLoot>d__10(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || num == 1)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<>7__wrap2 = null;
<>1__state = -2;
}
private bool MoveNext()
{
try
{
switch (<>1__state)
{
default:
return false;
case 0:
{
<>1__state = -1;
IEnumerable<Drop> enumerable = charDrop.m_drops.BossLootExceptTrophy();
<lvlMult>5__2 = ((!Object.op_Implicit((Object)(object)charDrop.m_character)) ? 1 : ((int)Mathf.Max(1f, Mathf.Pow(2f, (float)(charDrop.m_character.GetLevel() - 1)))));
<>7__wrap2 = enumerable.GetEnumerator();
<>1__state = -3;
break;
}
case 1:
<>1__state = -3;
break;
}
while (<>7__wrap2.MoveNext())
{
Drop current = <>7__wrap2.Current;
int num = (current.m_dontScale ? Random.Range(current.m_amountMin, current.m_amountMax) : Game.instance.ScaleDrops(current.m_prefab, current.m_amountMin, current.m_amountMax));
if (current.m_levelMultiplier)
{
num *= <lvlMult>5__2;
}
if (current.m_onePerPlayer)
{
num = Math.Min(ZNet.instance.GetNrOfPlayers(), 100);
}
if (num > 0)
{
<>2__current = new KeyValuePair<GameObject, int>(current.m_prefab, num);
<>1__state = 1;
return true;
}
}
<>m__Finally1();
<>7__wrap2 = null;
return false;
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
if (<>7__wrap2 != null)
{
<>7__wrap2.Dispose();
}
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<KeyValuePair<GameObject, int>> IEnumerable<KeyValuePair<GameObject, int>>.GetEnumerator()
{
<GetBossLoot>d__10 <GetBossLoot>d__;
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
<GetBossLoot>d__ = this;
}
else
{
<GetBossLoot>d__ = new <GetBossLoot>d__10(0);
}
<GetBossLoot>d__.charDrop = <>3__charDrop;
return <GetBossLoot>d__;
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<KeyValuePair<GameObject, int>>)this).GetEnumerator();
}
}
public static bool IsWorldBoss(this Character character)
{
if (character.IsBoss())
{
return Configs.TrophyToBoss.Values.Contains(character.m_nview.GetPrefabName());
}
return false;
}
public static BossStone GetBossStone(this ItemStand itemStand)
{
return ((Component)itemStand).GetComponentInParent<BossStone>();
}
public static void InvokeSacrifice(this BossStone bossStone)
{
State.BroadcastSacrifice(bossStone);
if (Configs.SacrificeTrophyForBossLoot.Value)
{
Timing.Delay((MonoBehaviour)(object)bossStone, 12f, (Action)bossStone.SpawnLoot);
}
}
public static Character GetBoss(this BossStone bossStone)
{
ItemDrop trophy = bossStone.GetTrophy();
return ZNetScene.instance.GetPrefab(Configs.TrophyToBoss[ItemDataExt.GetPrefabName(trophy)]).GetComponent<Character>();
}
public static ItemDrop GetTrophy(this BossStone bossStone)
{
return bossStone.m_itemStand.m_supportedItems[0];
}
public static bool IsBossStoneActive(this ItemStand itemStand, Player? player)
{
if (!ItemStandExt.IsBossStone(itemStand))
{
return false;
}
if (!ZenMod<Plugin>.Initialized)
{
return false;
}
if (!Configs.PerPlayerBossStones.Value)
{
return itemStand.HaveAttachment();
}
if (Object.op_Implicit((Object)(object)player))
{
return ((Humanoid)player).HaveUniqueKey(((Object)itemStand.m_guardianPower).name);
}
return false;
}
public static bool IsNear(this Player player, BossStone stone)
{
//IL_0006: 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)
if (Location.GetLocation(((Component)stone).transform.position, true).IsInside(((Component)player).transform.position, 0f, false))
{
return true;
}
Logging<Plugin>.Info((object)("Outside area: " + player.GetPlayerName()), 0);
return false;
}
public static void ActivateBossStone(this Player player, BossStone bossStone)
{
string name = ((Object)bossStone.m_itemStand.m_guardianPower).name;
if (!((Humanoid)player).HaveUniqueKey(name))
{
((Humanoid)player).AddUniqueKey(name);
}
}
public static ItemData? FindTrophyIn(this ItemStand itemStand, Inventory inventory)
{
string prefabName = ItemDataExt.GetPrefabName(itemStand.m_supportedItems[0]);
return inventory.GetItem(prefabName, -1, true);
}
private static void SpawnLoot(this BossStone bossStone)
{
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: 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_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
Character boss = bossStone.GetBoss();
Logging<Plugin>.Info((object)("Spawn rewards for " + ((Object)boss).name), 0);
CharacterDrop component = ((Component)boss).GetComponent<CharacterDrop>();
if (Configs.BossTrophyOnePerPlayer.Value)
{
foreach (Drop drop in component.m_drops)
{
drop.m_onePerPlayer = false;
}
}
List<KeyValuePair<GameObject, int>> list = GetBossLoot(component).ToList();
if (Logging<Plugin>.IsEnabled)
{
foreach (KeyValuePair<GameObject, int> item in list)
{
Logging<Plugin>.Info((object)$"{((Object)item.Key).name} = {item.Value}", 0);
}
}
Transform transform = ((Component)bossStone.m_itemStand).transform;
Vector3 position = transform.position;
position.y = ((Component)Player.m_localPlayer).transform.position.y + 0.5f;
Vector3 val = position;
Vector3 val2 = transform.forward * 3f;
CharacterDrop.DropItems(list, val + val2, 0.25f);
}
[IteratorStateMachine(typeof(<GetBossLoot>d__10))]
private static IEnumerable<KeyValuePair<GameObject, int>> GetBossLoot(CharacterDrop charDrop)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <GetBossLoot>d__10(-2)
{
<>3__charDrop = charDrop
};
}
internal static IEnumerable<Drop> BossLootExceptTrophy(this List<Drop> drops)
{
return drops.Where((Drop d) => d.m_chance >= 1f && Object.op_Implicit((Object)(object)d.m_prefab) && !Configs.TrophyToBoss.ContainsKey(((Object)d.m_prefab).name));
}
}
[HarmonyPatch]
internal static class PatchMisc
{
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerController), "TakeInput")]
private static void PlayerController_TakeInput(bool look, ref bool __result)
{
if (Configs.EmoteToReceivePower.Value != PowerEmotes.None)
{
__result = __result && (!State.IsReceivingPower || look);
}
}
}
[HarmonyPatch]
public static class PatchItemStand
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(ItemStand), "Awake")]
private static IEnumerable<CodeInstruction> ItemStand_Awake_Transpile(IEnumerable<CodeInstruction> codes)
{
MethodInfo methodInfo = AccessTools.Method(typeof(MonoBehaviour), "InvokeRepeating", (Type[])null, (Type[])null);
Action<ItemStand, string, float, float> action = ItemStandAwake_InvokeRepeating_Intercept;
return Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method);
}
private static void ItemStandAwake_InvokeRepeating_Intercept(ItemStand itemStand, string methodName, float time, float repeatRate)
{
if (ItemStandExt.IsBossStone(itemStand) && Configs.PerPlayerBossStones.Value && !Object.op_Implicit((Object)(object)Player.m_localPlayer))
{
repeatRate = 1f;
}
((MonoBehaviour)itemStand).InvokeRepeating(methodName, time, repeatRate);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemStand), "GetHoverText")]
private static void ItemStand_GetHoverText(ItemStand __instance, ref string __result)
{
if (!ItemStandExt.IsBossStone(__instance))
{
return;
}
__result = __result.Replace(StringExt.Localize("\n$guardianstone_hook_alreadyactive"), string.Empty);
if (Configs.SacrificeTrophyForBossLoot.Value && __instance.IsBossStoneActive(Player.m_localPlayer))
{
if (State.IsInvokingSacrifice)
{
__result = string.Empty;
}
if (!(__result == string.Empty) && __instance.FindTrophyIn(((Humanoid)Player.m_localPlayer).GetInventory()) != null)
{
__result += StringExt.Localize("\n" + UI.PromptInteractAlt + " $prop_offerbowl_makeoffer");
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ItemStand), "Interact")]
private static void ItemStand_Interact_Prefix(ItemStand __instance, bool alt, bool hold, ref bool __runOriginal, ref bool __result)
{
if (!ItemStandExt.IsBossStone(__instance) || !Configs.SacrificeTrophyForBossLoot.Value || !alt || hold)
{
return;
}
__runOriginal = false;
if (!State.IsInvokingSacrifice)
{
Player localPlayer = Player.m_localPlayer;
ItemData val = __instance.FindTrophyIn(((Humanoid)localPlayer).GetInventory());
if (val == null)
{
((Character)localPlayer).Message((MessageType)2, "$piece_itemstand_missingitem", 0, (Sprite)null);
Logging<Plugin>.Info((object)"Missing trophy from inventory", 0);
return;
}
((Humanoid)localPlayer).GetInventory().RemoveOneItem(val);
Logging<Plugin>.Info((object)("Trophy offered: " + ItemDataExt.GetPrefabName(val)), 0);
__instance.GetBossStone().InvokeSacrifice();
__result = true;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemStand), "Interact")]
private static void ItemStand_Interact_Postfix(ItemStand __instance, bool alt, bool hold, bool __result)
{
if (ItemStandExt.IsBossStone(__instance) && __result && !(alt || hold) && !State.IsInvokingSacrifice && Configs.EmoteToReceivePower.Value != PowerEmotes.None)
{
string text = Configs.EmoteToReceivePower.Value.ToString().ToLower();
Player.m_localPlayer.StartEmote(text, true);
State.IsReceivingPower = true;
Timing.Delay((MonoBehaviour)(object)__instance, __instance.m_powerActivationDelay, (Action)delegate
{
State.IsReceivingPower = false;
((Character)Player.m_localPlayer).StopEmote();
});
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ItemStand), "UseItem")]
private static void ItemStand_UseItem_Prefix(ItemStand __instance, Humanoid user, ItemData item, ref bool __result, ref bool __runOriginal)
{
if (!ItemStandExt.IsBossStone(__instance) || !Configs.PerPlayerBossStones.Value)
{
return;
}
__runOriginal = false;
__result = false;
if (!State.IsInvokingSacrifice)
{
__result = true;
if (__instance.CanAttach(item) && (!__instance.HaveAttachment() || Configs.SacrificeTrophyForBossLoot.Value))
{
((Humanoid)Player.m_localPlayer).GetInventory().RemoveOneItem(item);
__instance.GetBossStone().InvokeSacrifice();
}
else
{
((Character)user).Message((MessageType)2, "$piece_itemstand_cantattach", 0, (Sprite)null);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemStand), "UseItem")]
private static void ItemStand_UseItem_Postfix(ItemStand __instance, bool __result)
{
if (ItemStandExt.IsBossStone(__instance) && !Configs.PerPlayerBossStones.Value && __result)
{
__instance.GetBossStone().InvokeSacrifice();
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ItemStand), "UpdateVisual")]
private static void ItemStand_UpdateVisual(ItemStand __instance, ref bool __runOriginal)
{
if (ItemStandExt.IsBossStone(__instance) && Configs.PerPlayerBossStones.Value)
{
Player localPlayer = Player.m_localPlayer;
string name = ((Object)__instance.m_supportedItems[0]).name;
int orientation = __instance.GetOrientation();
__instance.SetVisualItem(__instance.IsBossStoneActive(localPlayer) ? name : string.Empty, 0, 1, orientation);
__runOriginal = false;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ItemStand), "HaveAttachment")]
private static void ItemStand_HaveAttachment(ItemStand __instance, ref bool __runOriginal, ref bool __result)
{
if (ItemStandExt.IsBossStone(__instance) && Configs.PerPlayerBossStones.Value)
{
Player localPlayer = Player.m_localPlayer;
__result = __instance.IsBossStoneActive(localPlayer);
__runOriginal = false;
}
}
}
[HarmonyPatch]
public static class PatchCharacterDrop
{
[HarmonyPostfix]
[HarmonyPatch(typeof(CharacterDrop), "Start")]
private static void CharacterDrop_Start(CharacterDrop __instance)
{
if (__instance.m_character.IsWorldBoss() && Configs.SacrificeTrophyForBossLoot.Value)
{
Drop val = ((IEnumerable<Drop>)__instance.m_drops).FirstOrDefault((Func<Drop, bool>)((Drop drop) => Configs.TrophyToBoss.ContainsKey(((Object)drop.m_prefab).name)));
if (val != null)
{
val.m_onePerPlayer = Configs.BossTrophyOnePerPlayer.Value;
}
else
{
Logging<Plugin>.Warning((object)("Trophy not found in loot table: " + ((Object)__instance.m_character).name + ", can not sacrifice trophy for loot"), 0);
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
private static void CharacterDrop_GenerateDropList(CharacterDrop __instance)
{
if (Configs.SacrificeTrophyForBossLoot.Value && Object.op_Implicit((Object)(object)__instance.m_character) && __instance.m_character.IsWorldBoss())
{
List<Drop> drops = __instance.m_drops;
IEnumerable<Drop> source = drops.Except(drops.BossLootExceptTrophy());
__instance.m_drops = source.ToList();
}
}
}
public enum PowerEmotes
{
None = -1,
Kneel = 15,
Roar = 17,
Laugh = 16,
Challange = 2,
Flex = 12,
Bow = 8,
Headbang = 14,
Cheer = 3,
Cower = 9,
Toast = 21,
Despair = 11,
ThumbsUp = 5,
Cry = 10,
Shrug = 18
}
[BepInPlugin("ZenDragon.ZenBossStone", "ZenBossStone", "0.3.4")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
internal class Plugin : ZenMod<Plugin>
{
public const string PluginName = "ZenBossStone";
public const string PluginVersion = "0.3.4";
public const string PluginGUID = "ZenDragon.ZenBossStone";
protected override void Setup()
{
((ZenMod)this).RunOnServer = true;
Commands.Init();
base.ConfigSync += Configs.Init;
}
protected override void TitleScene(bool isFirstBoot)
{
}
protected override void HotRestore()
{
Configs.Init();
}
protected override void WorldStart()
{
if (Configs.AutoSetWorldModifierPlayerEvents.Value)
{
SetWorldModifierPlayerEvents();
}
State.RegisterRPC();
Commands.RegisterRPC();
}
protected override void Shutdown()
{
State.UnregisterRPC();
Commands.UnregisterRPC();
}
private static void SetWorldModifierPlayerEvents()
{
if (ZNet.instance.IsServer())
{
ZoneSystem.instance.SetGlobalKey((GlobalKeys)13);
Logging<Plugin>.Message((object)"World modifier enabled: PlayerEvents", 0);
}
}
}
public static class State
{
public static bool IsReceivingPower;
private static readonly HashSet<string> InvokingSacrifice = new HashSet<string>();
public static bool IsInvokingSacrifice => InvokingSacrifice.Count > 0;
private static void SetInvokingSacrifice(BossStone bossStone)
{
string prefabName = Utils.GetPrefabName(((Object)bossStone).name);
InvokingSacrifice.Add(prefabName);
Timing.Delay((MonoBehaviour)(object)bossStone, 12f, (Action)delegate
{
InvokingSacrifice.Remove(prefabName);
});
}
public static void RegisterRPC()
{
ZRoutedRpc.instance.Register<ZDOID>("RPC_BossStoneSacrifice", (Action<long, ZDOID>)RPC_BossStoneSacrifice);
}
public static void UnregisterRPC()
{
ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_BossStoneSacrifice");
}
public static void BroadcastSacrifice(BossStone bossStone)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
ZDO zDO = bossStone.m_itemStand.m_nview.GetZDO();
ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RPC_BossStoneSacrifice", new object[1] { zDO.m_uid });
}
private static void RPC_BossStoneSacrifice(long sender, ZDOID itemStandID)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
GameObject val = ZNetScene.instance.FindInstance(itemStandID);
if (!Object.op_Implicit((Object)(object)val))
{
return;
}
BossStone componentInParent = val.GetComponentInParent<BossStone>();
Player localPlayer = Player.m_localPlayer;
if (Configs.SacrificeTrophyForBossLoot.Value)
{
componentInParent.m_active = false;
}
if (localPlayer.IsNear(componentInParent))
{
if (Configs.PerPlayerBossStones.Value)
{
localPlayer.ActivateBossStone(componentInParent);
}
SetInvokingSacrifice(componentInParent);
}
}
}
}