using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SlayerSkills")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SlayerSkills")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9f8a1b6e-6d0e-4dab-bbd8-9ed433836544")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
internal sealed class ConfigurationManagerAttributes
{
public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);
public bool? ShowRangeAsPercent;
public Action<ConfigEntryBase> CustomDrawer;
public CustomHotkeyDrawerFunc CustomHotkeyDrawer;
public bool? Browsable;
public string Category;
public object DefaultValue;
public bool? HideDefaultButton;
public bool? HideSettingName;
public string Description;
public string DispName;
public int? Order;
public bool? ReadOnly;
public bool? IsAdvanced;
public Func<object, string> ObjToStr;
public Func<string, object> StrToObj;
}
namespace neobotics.ValheimMods;
internal class DebugUtils
{
public static void ObjectInspector(object o)
{
if (o == null)
{
Debug.Log((object)"Object is null");
return;
}
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
Type type = o.GetType();
Debug.Log((object)(o.ToString() + " Type " + type.Name));
PropertyInfo[] properties = type.GetProperties(bindingAttr);
foreach (PropertyInfo propertyInfo in properties)
{
Debug.Log((object)$"{type.Name}.{propertyInfo.Name} = {propertyInfo.GetValue(o)}");
}
FieldInfo[] fields = type.GetFields(bindingAttr);
foreach (FieldInfo field in fields)
{
FieldPrinter(o, type, field);
}
}
public static void MethodInspector(object o)
{
if (o == null)
{
Debug.Log((object)"Object is null");
return;
}
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
Type type = o.GetType();
Debug.Log((object)(o.ToString() + " Type " + type.Name));
MethodInfo[] methods = type.GetMethods(bindingAttr);
foreach (MethodInfo methodInfo in methods)
{
methodInfo.GetParameters();
string arg = string.Join(", ", (from x in methodInfo.GetParameters()
select x.ParameterType?.ToString() + " " + x.Name).ToArray());
Debug.Log((object)$"{methodInfo.ReturnType} {methodInfo.Name} ({arg})");
}
}
private static void ItemDataInspector(ItemData item)
{
ObjectInspector(item);
ObjectInspector(item.m_shared);
}
private static void FieldPrinter(object o, Type t, FieldInfo field)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected O, but got Unknown
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Expected O, but got Unknown
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Expected O, but got Unknown
try
{
if (field.FieldType == typeof(ItemData))
{
ItemData val = (ItemData)field.GetValue(o);
if (val != null)
{
ItemDataInspector(val);
}
else
{
Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
}
}
else if (field.FieldType == typeof(Transform))
{
Transform val2 = (Transform)field.GetValue(o);
if ((Object)(object)val2 != (Object)null)
{
Debug.Log((object)("\tTransform.parent = " + ((Object)val2.parent).name));
}
else
{
Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
}
}
else if (field.FieldType == typeof(EffectList))
{
EffectList val3 = (EffectList)field.GetValue(o);
if (val3 != null)
{
Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}:");
EffectData[] effectPrefabs = val3.m_effectPrefabs;
foreach (EffectData val4 in effectPrefabs)
{
Debug.Log((object)("\tEffectData.m_prefab = " + ((Object)val4.m_prefab).name));
}
}
else
{
Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]");
}
}
else
{
Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}");
}
}
catch (Exception)
{
Debug.Log((object)("Exception accessing " + t?.Name + "." + field?.Name));
}
}
public static void GameObjectInspector(GameObject go)
{
Debug.Log((object)("\n\nInspecting GameObject " + ((Object)go).name));
ObjectInspector(go);
Component[] componentsInChildren = go.GetComponentsInChildren<Component>();
foreach (Component val in componentsInChildren)
{
try
{
string obj = ((val != null) ? ((Object)val).name : null);
object obj2;
if (val == null)
{
obj2 = null;
}
else
{
Transform transform = val.transform;
if (transform == null)
{
obj2 = null;
}
else
{
Transform parent = transform.parent;
obj2 = ((parent != null) ? ((Object)parent).name : null);
}
}
Debug.Log((object)("\n\nInspecting Component " + obj + " with parent " + (string?)obj2));
ObjectInspector(val);
}
catch (Exception)
{
}
}
}
public static void ComponentInspector(Component c)
{
Debug.Log((object)("\n\nInspecting Component " + ((Object)c).name));
ObjectInspector(c);
}
public static void EffectsInspector(EffectList e)
{
EffectData[] effectPrefabs = e.m_effectPrefabs;
Debug.Log((object)$"Effect list has effects {e.HasEffects()} count {effectPrefabs.Length}");
EffectData[] array = effectPrefabs;
foreach (EffectData val in array)
{
Debug.Log((object)$"Effect Data {val} prefab name {((Object)val.m_prefab).name} prefab GameObject name {((Object)val.m_prefab.gameObject).name}");
}
}
public static void PrintInventory()
{
foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems())
{
Debug.Log((object)allItem.m_shared.m_name);
}
}
public static void PrintAllObjects()
{
ZNetScene.instance.m_prefabs.ForEach(delegate(GameObject x)
{
Debug.Log((object)("GameObject " + ((Object)x).name));
});
}
public static void PrintAllCharacters()
{
Character.GetAllCharacters().ForEach(delegate(Character x)
{
Debug.Log((object)("Character " + ((Object)x).name));
});
}
}
public class DelegatedConfigEntry<T> : DelegatedConfigEntryBase
{
private ConfigEntry<T> _entry;
private EventHandler rootHandler;
private Action<object, EventArgs> clientDelegate;
private Logging Log;
public ConfigEntry<T> ConfigEntry
{
get
{
return _entry;
}
set
{
_entry = value;
if (_entry != null && rootHandler != null)
{
_entry.SettingChanged += rootHandler;
}
Name = ((ConfigEntryBase)_entry).Definition.Key;
Section = ((ConfigEntryBase)_entry).Definition.Section;
ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue();
Log.Trace("Set " + Section + " " + Name + " to serialized value " + ServerValue);
}
}
public T Value
{
get
{
return _entry.Value;
}
set
{
_entry.Value = value;
}
}
public DelegatedConfigEntry(bool useServerDelegate = false)
: this((Action<object, EventArgs>)null, useServerDelegate)
{
}
public DelegatedConfigEntry(Action<object, EventArgs> delegateHandler, bool useServerDelegate = false)
{
Log = Logging.GetLogger();
Log.Trace("DelegatedConfigEntry");
if (delegateHandler != null)
{
clientDelegate = delegateHandler;
}
if (useServerDelegate)
{
Log.Trace("Configuring server delegate");
rootHandler = delegate(object s, EventArgs e)
{
ServerDelegate(s, e);
};
ServerConfiguration.ServerDelegatedEntries.Add(this);
}
else if (clientDelegate != null)
{
rootHandler = delegate(object s, EventArgs e)
{
clientDelegate(s, e);
};
}
}
private void ServerDelegate(object sender, EventArgs args)
{
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Expected O, but got Unknown
Logging.GetLogger().Trace("ServerDelegate");
_entry.SettingChanged -= rootHandler;
ZNet instance = ZNet.instance;
bool? flag = ((instance != null) ? new bool?(instance.IsServer()) : null);
if (flag.HasValue)
{
if (flag == false)
{
if (ServerValue != null)
{
((ConfigEntryBase)_entry).SetSerializedValue(ServerValue);
}
}
else
{
ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue();
ServerConfiguration.Instance.SendConfigToAllClients(sender, (SettingChangedEventArgs)args);
}
}
if (clientDelegate != null)
{
clientDelegate(sender, args);
}
_entry.SettingChanged += rootHandler;
}
public void EnableHandler(bool setActive)
{
if (setActive)
{
_entry.SettingChanged += rootHandler;
}
else
{
_entry.SettingChanged -= rootHandler;
}
}
public bool IsKeyPressed()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
if (ConfigEntry is ConfigEntry<KeyboardShortcut> val)
{
KeyboardShortcut value = val.Value;
foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
{
if (!Input.GetKey(modifier))
{
return false;
}
}
if (!Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
{
return false;
}
return true;
}
Log.Error("Keyboard read attempted on non-KeyboardShortcut config.");
return false;
}
public bool IsKeyDown()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
if (ConfigEntry is ConfigEntry<KeyboardShortcut> val)
{
KeyboardShortcut value = val.Value;
foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
{
if (!Input.GetKey(modifier))
{
return false;
}
}
if (!Input.GetKey(((KeyboardShortcut)(ref value)).MainKey))
{
return false;
}
return true;
}
Log.Error("Keyboard read attempted on non-KeyboardShortcut config.");
return false;
}
public bool IsKeyReleased()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
if (ConfigEntry is ConfigEntry<KeyboardShortcut> val)
{
KeyboardShortcut value = val.Value;
foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
{
if (!Input.GetKeyUp(modifier))
{
return false;
}
}
if (!Input.GetKeyUp(((KeyboardShortcut)(ref value)).MainKey))
{
return false;
}
return true;
}
Log.Error("Keyboard read attempted on non-KeyboardShortcut config.");
return false;
}
}
public class DelegatedConfigEntryBase
{
public string Name;
public string Section;
public string ServerValue;
}
internal class HarmonyHelper
{
public enum PatchType
{
Prefix,
Postfix,
Transpiler,
Finalizer
}
private static Dictionary<string, string> detectionSet = new Dictionary<string, string>();
private static Dictionary<string, string> unpatchMods = new Dictionary<string, string>();
public static void GetDetectionSet(Dictionary<string, string> harmonyIds)
{
Logging logger = Logging.GetLogger();
foreach (KeyValuePair<string, string> harmonyId in harmonyIds)
{
if (Harmony.HasAnyPatches(harmonyId.Key))
{
logger.Debug("Detected " + harmonyId.Value + " from Harmony");
if (!detectionSet.ContainsKey(harmonyId.Key))
{
detectionSet.Add(harmonyId.Key, harmonyId.Value);
}
}
else if (Chainloader.PluginInfos.ContainsKey(harmonyId.Key))
{
logger.Debug("Detected " + harmonyId.Value + " from BepInEx");
if (!detectionSet.ContainsKey(harmonyId.Key))
{
detectionSet.Add(harmonyId.Key, harmonyId.Value);
}
}
}
}
public static void AddExclusion(string key)
{
if (detectionSet.ContainsKey(key))
{
unpatchMods.Add(key, detectionSet[key]);
}
}
public static void UnpatchMods(Harmony harmony)
{
Logging logger = Logging.GetLogger();
foreach (KeyValuePair<string, string> unpatchMod in unpatchMods)
{
logger.Warning("Not compatible with " + unpatchMod.Value);
harmony.UnpatchAll(unpatchMod.Key);
detectionSet.Remove(unpatchMod.Key);
logger.Warning("Disabled " + unpatchMod.Value);
}
}
public static bool IsModDetected(string key)
{
return detectionSet.ContainsKey(key);
}
public static bool IsModNameDetected(string value)
{
return detectionSet.ContainsValue(value);
}
public static bool TryGetDetectedModName(string key, out string mod)
{
return detectionSet.TryGetValue(key, out mod);
}
public static bool TryGetDetectedModKey(string value, out string key)
{
key = null;
foreach (string key2 in detectionSet.Keys)
{
if (detectionSet[key2] == value)
{
key = key2;
return true;
}
}
return false;
}
public static string AddAnonymousPatch(string baseMethodName, PatchType patchType, string modName, string patchMethodName = null)
{
string text = null;
int num = 0;
Logging logger = Logging.GetLogger();
foreach (MethodBase item in Harmony.GetAllPatchedMethods().ToList())
{
MethodBaseExtensions.HasMethodBody(item);
Patches patchInfo = Harmony.GetPatchInfo(item);
ReadOnlyCollection<Patch> readOnlyCollection = patchInfo.Prefixes;
switch (patchType)
{
case PatchType.Postfix:
readOnlyCollection = patchInfo.Postfixes;
break;
case PatchType.Prefix:
readOnlyCollection = patchInfo.Prefixes;
break;
case PatchType.Transpiler:
readOnlyCollection = patchInfo.Transpilers;
break;
case PatchType.Finalizer:
readOnlyCollection = patchInfo.Finalizers;
break;
}
foreach (Patch item2 in readOnlyCollection)
{
if (!item2.owner.StartsWith("harmony-auto") || !(item.Name == baseMethodName))
{
continue;
}
if (patchMethodName != null)
{
if (item2.PatchMethod.Name == patchMethodName)
{
num++;
text = item2.owner;
}
}
else
{
num++;
text = item2.owner;
}
}
if (num == 1)
{
detectionSet.Add(text, modName);
logger.Info($"Added unique anonymous {baseMethodName} {patchType}: {text} as {modName}");
}
else if (num > 1)
{
text = null;
logger.Warning($"Found multiple anonymous {baseMethodName} {patchType} entries. Can't identify correct patch to remove or modify.");
}
}
if (num == 0)
{
logger.Info("No patch found for " + modName);
}
return text;
}
}
public class Logging
{
public enum LogLevels
{
Critical,
Error,
Warning,
Info,
Debug,
Trace
}
private static Logging _logger;
public LogLevels LogLevel { get; set; }
public string ModName { get; set; }
private Logging(LogLevels level, string name)
{
LogLevel = level;
ModName = name;
}
public static Logging GetLogger(LogLevels level, string name)
{
if (_logger == null)
{
_logger = new Logging(level, name);
}
return _logger;
}
public static Logging GetLogger()
{
if (_logger == null)
{
return GetLogger(LogLevels.Info, Assembly.GetExecutingAssembly().FullName);
}
return _logger;
}
public void Trace(string msg)
{
if (LogLevel >= LogLevels.Trace)
{
Debug.Log((object)Message(msg));
}
}
public void Debug(string msg)
{
if (LogLevel >= LogLevels.Debug)
{
Debug.Log((object)Message(msg));
}
}
public void Info(string msg)
{
if (LogLevel >= LogLevels.Info)
{
Debug.Log((object)Message(msg));
}
}
public void Warning(string msg)
{
if (LogLevel >= LogLevels.Warning)
{
Debug.LogWarning((object)Message(msg));
}
}
public void Error(string msg)
{
if (LogLevel >= LogLevels.Error)
{
Debug.LogWarning((object)Message(msg));
}
}
public void Error(Exception e)
{
Error(e, stackTrace: false);
}
public void Error(Exception e, bool stackTrace)
{
if (LogLevel >= LogLevels.Error)
{
Debug.LogWarning((object)Message(e.Message));
if (stackTrace)
{
Debug.LogWarning((object)e.StackTrace);
}
}
}
public void Critical(Exception e)
{
if (LogLevel >= LogLevels.Critical)
{
Debug.LogError((object)Message(e.Message));
Debug.LogError((object)e.StackTrace);
}
}
private string Message(string msg)
{
return ModName + ": " + msg;
}
}
public class ServerConfiguration
{
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
private static class ZNet_OnNewConnection_Patch
{
private static void Postfix(ZNet __instance, ZNetPeer peer)
{
Log.Debug("ZNet OnNewConnection postfix");
if (!__instance.IsServer())
{
try
{
Log.Debug("Client registered RPC_ClientConfigReceiver");
peer.m_rpc.Register<ZPackage>("ClientConfigReceiver." + GetPluginGuid(), (Action<ZRpc, ZPackage>)RPC_ClientConfigReceiver);
return;
}
catch (Exception)
{
Log.Warning("Failed to register RPC");
return;
}
}
try
{
SendConfigToClient(peer);
}
catch (Exception)
{
Log.Warning("Error sending server configuration to client");
}
}
}
public static List<DelegatedConfigEntryBase> ServerDelegatedEntries = new List<DelegatedConfigEntryBase>();
private static ConfigFile LocalConfig;
private static BaseUnityPlugin Mod;
private static ServerConfiguration _instance;
private static Logging Log;
public static bool IsSetup = false;
private const string NOT_CONFIGURED = "ServerConfiguration not initialized. Setup first.";
public static ServerConfiguration Instance
{
get
{
if (_instance == null)
{
_instance = new ServerConfiguration();
}
return _instance;
}
}
private ServerConfiguration()
{
}
public void Setup(ConfigFile config, BaseUnityPlugin modInstance)
{
LocalConfig = config;
Log = Logging.GetLogger();
Log.Trace("ServerConfiguration Setup");
Mod = modInstance;
IsSetup = true;
}
public static string GetPluginGuid()
{
return Mod.Info.Metadata.GUID;
}
public static void RPC_ClientConfigReceiver(ZRpc zrpc, ZPackage package)
{
if (!IsSetup)
{
Log.Error("ServerConfiguration not initialized. Setup first.");
return;
}
Log.Debug("ClientConfigReceiver");
string section;
string name;
while (package.GetPos() < package.Size())
{
section = package.ReadString();
name = package.ReadString();
string text = package.ReadString();
Log.Trace("Reading " + section + " " + name + " value " + text + " from ZPackage");
DelegatedConfigEntryBase delegatedConfigEntryBase = ServerDelegatedEntries.Find((DelegatedConfigEntryBase e) => e.Name == name && e.Section == section);
if (delegatedConfigEntryBase != null)
{
Log.Trace("Found DCEB on client and setting to server value " + text);
delegatedConfigEntryBase.ServerValue = text;
}
ConfigEntryBase val = LocalConfig[section, name];
if (val != null)
{
Log.Trace("Found local CEB and setting underlying config value " + text);
val.SetSerializedValue(text);
}
}
}
internal static void WriteConfigEntries(ZPackage zpkg)
{
foreach (DelegatedConfigEntryBase serverDelegatedEntry in ServerDelegatedEntries)
{
Log.Trace("Writing " + serverDelegatedEntry.Section + " " + serverDelegatedEntry.Name + " value " + serverDelegatedEntry.ServerValue + " to ZPackage");
zpkg.Write(serverDelegatedEntry.Section);
zpkg.Write(serverDelegatedEntry.Name);
zpkg.Write(serverDelegatedEntry.ServerValue);
}
}
internal static void SendConfigToClient(ZNetPeer peer)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
if (!IsSetup)
{
Log.Error("ServerConfiguration not initialized. Setup first.");
return;
}
Log.Debug("ServerSendConfigToClient");
ZPackage val = new ZPackage();
WriteConfigEntries(val);
peer.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { val });
}
public void SendConfigToAllClients(object o, SettingChangedEventArgs e)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
if (!IsSetup)
{
Log.Error("ServerConfiguration not initialized. Setup first.");
}
else if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZNet.instance.GetPeerConnections() > 0)
{
Log.Debug("SendConfigToAllClients");
ZPackage zpkg = new ZPackage();
WriteConfigEntries(zpkg);
((MonoBehaviour)Mod).StartCoroutine(_instance.Co_BroadcastConfig(zpkg));
}
}
private IEnumerator Co_BroadcastConfig(ZPackage zpkg)
{
Log.Debug("Co_BroadcastConfig");
List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
foreach (ZNetPeer item in connectedPeers)
{
if (item != ZNet.instance.GetServerPeer())
{
item.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { zpkg });
}
yield return null;
}
}
}
internal class Utils
{
public static TEnum Guardrails<TEnum>(string value, TEnum enumDefault) where TEnum : struct
{
if (Enum.TryParse<TEnum>(value, ignoreCase: true, out var result))
{
return result;
}
return enumDefault;
}
public static int Guardrails(int value, int lbound, int ubound)
{
if (value < lbound)
{
return lbound;
}
if (value > ubound)
{
return ubound;
}
return value;
}
public static float Guardrails(float value, float lbound, float ubound)
{
if (value < lbound)
{
return lbound;
}
if (value > ubound)
{
return ubound;
}
return value;
}
public static string UnClonifiedName(string name)
{
if (name == null)
{
return null;
}
int num = name.IndexOf("(Clone)");
if (num < 1)
{
return name;
}
return name.Substring(0, num);
}
public static void SetTranslator(int id, string idText)
{
typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(Localization.instance, new object[2]
{
"skill_" + id,
idText
});
}
public static string GetTranslated(int id)
{
Logging.GetLogger().Debug(string.Format("Got translation for id {0} to {1}", id, Localization.instance.Localize("skill_" + id)));
return Localization.instance.Localize("$skill_" + id);
}
public static Sprite GetPrefabIcon(string prefabName)
{
Sprite result = null;
GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
ItemDrop val = default(ItemDrop);
if ((Object)(object)itemPrefab != (Object)null && itemPrefab.TryGetComponent<ItemDrop>(ref val))
{
result = val.m_itemData.GetIcon();
}
return result;
}
public static Player GetPlayerByZDOID(ZDOID zid)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
foreach (Player allPlayer in Player.GetAllPlayers())
{
ZDOID zDOID = ((Character)allPlayer).GetZDOID();
if (((ZDOID)(ref zDOID)).Equals(zid))
{
return allPlayer;
}
}
return null;
}
public static Character GetCharacterByZDOID(string cid)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
foreach (Character allCharacter in Character.GetAllCharacters())
{
ZDOID zDOID = allCharacter.GetZDOID();
if (((object)(ZDOID)(ref zDOID)).ToString().Equals(cid))
{
return allCharacter;
}
}
return null;
}
public static Character GetCharacterByZDOID(ZDOID cid)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
foreach (Character allCharacter in Character.GetAllCharacters())
{
ZDOID zDOID = allCharacter.GetZDOID();
if (((ZDOID)(ref zDOID)).Equals(cid))
{
return allCharacter;
}
}
return null;
}
public static ZNetPeer GetPeerByRPC(ZRpc rpc)
{
foreach (ZNetPeer peer in ZNet.instance.GetPeers())
{
if (peer.m_rpc == rpc)
{
return peer;
}
}
return null;
}
public static List<GameObject> GetGameObjectsOfType(Type t)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
List<GameObject> list = new List<GameObject>();
Object[] array = Object.FindObjectsOfType(t);
foreach (Object val in array)
{
list.Add(((Component)val).gameObject);
}
return list;
}
public static GameObject GetClosestGameObjectOfType(Type t, Vector3 point, float radius)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return GetGameObjectsOfTypeInRangeByDistance(t, point, radius)?[0];
}
public static List<GameObject> GetGameObjectsOfTypeInRangeByDistance(Type t, Vector3 point, float radius)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
List<KeyValuePair<GameObject, float>> list = new List<KeyValuePair<GameObject, float>>();
List<GameObject> gameObjectsOfTypeInRange = GetGameObjectsOfTypeInRange(t, point, radius);
if (gameObjectsOfTypeInRange.Count > 0)
{
foreach (GameObject item in gameObjectsOfTypeInRange)
{
list.Add(new KeyValuePair<GameObject, float>(item, Vector3.Distance(item.transform.position, point)));
}
list.Sort((KeyValuePair<GameObject, float> pair1, KeyValuePair<GameObject, float> pair2) => pair1.Value.CompareTo(pair2.Value));
return list.ConvertAll((KeyValuePair<GameObject, float> x) => x.Key);
}
return null;
}
public static List<GameObject> GetGameObjectsOfTypeInRange(Type t, Vector3 point, float radius)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
return (from x in GetGameObjectsOfType(t)
where Vector3.Distance(x.transform.position, point) < radius
select x).ToList();
}
public static float GetPointDepth(Vector3 p)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
return ZoneSystem.instance.m_waterLevel - GetSolidHeight(p);
}
public static List<string> GetDelimitedStringAsList(string delimitedString, char delimiter)
{
List<string> list = new List<string>();
string[] array = delimitedString.Split(new char[1] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
foreach (string text in array)
{
list.Add(text.Trim());
}
return list;
}
public static float GetSolidHeight(Vector3 p)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
int solidRayMask = ZoneSystem.instance.m_solidRayMask;
float result = 0f;
p.y += 1000f;
RaycastHit val = default(RaycastHit);
if (Physics.Raycast(p, Vector3.down, ref val, 2000f, solidRayMask) && !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody))
{
result = ((RaycastHit)(ref val)).point.y;
}
return result;
}
public static Transform FindChild(Transform aParent, string aName)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Expected O, but got Unknown
foreach (Transform item in aParent)
{
Transform val = item;
if (((Object)val).name == aName)
{
return val;
}
Transform val2 = FindChild(val, aName);
if ((Object)(object)val2 != (Object)null)
{
return val2;
}
}
return null;
}
public static Transform FindParent(Transform go)
{
while ((Object)(object)go.parent != (Object)null)
{
go = go.parent;
}
return go;
}
public static GameObject GetPrefabByHash(int prefabHash)
{
GameObject val = ObjectDB.instance.GetItemPrefab(prefabHash);
Logging logger = Logging.GetLogger();
if ((Object)(object)val != (Object)null)
{
logger.Debug("Found prefab in ObjectDB");
}
else
{
ZNetScene instance = ZNetScene.instance;
val = ((instance != null) ? instance.GetPrefab(prefabHash) : null);
if ((Object)(object)val != (Object)null)
{
logger.Debug("Found prefab in Scene");
}
}
return val;
}
public static GameObject GetPrefab(string prefabName)
{
GameObject val = ObjectDB.instance.GetItemPrefab(prefabName);
Logging logger = Logging.GetLogger();
if ((Object)(object)val != (Object)null)
{
logger.Debug("Found " + prefabName + " in ObjectDB");
}
else
{
ZNetScene instance = ZNetScene.instance;
val = ((instance != null) ? instance.GetPrefab(prefabName) : null);
if ((Object)(object)val != (Object)null)
{
logger.Debug("Found " + prefabName + " in Scene");
}
}
return val;
}
public static string SerializeFromDictionary<K, V>(string delimp, string delimc, IDictionary<K, V> dict)
{
if (dict == null)
{
return null;
}
IEnumerable<string> values = dict.Select(delegate(KeyValuePair<K, V> kvp)
{
KeyValuePair<K, V> keyValuePair = kvp;
string? obj = keyValuePair.Key?.ToString();
string text = delimc;
keyValuePair = kvp;
return obj + text + keyValuePair.Value;
});
return string.Join(delimp, values);
}
public static void DeserializeToDictionary<K, V>(string serializedString, string delimp, string delimc, ref IDictionary<K, V> dict)
{
if (dict == null)
{
return;
}
dict.Clear();
string[] separator = new string[1] { delimp };
string[] separator2 = new string[1] { delimc };
string[] array = serializedString.Split(separator, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < array.Length; i++)
{
string[] array2 = array[i].Split(separator2, StringSplitOptions.RemoveEmptyEntries);
if (array2.Length == 2)
{
dict.Add(TypedValue<K>(array2[0]), TypedValue<V>(array2[1]));
}
}
}
public static T TypedValue<T>(object a)
{
return (T)Convert.ChangeType(a, typeof(T));
}
public static bool CopyComponentToGameObject(Component original, ref GameObject destination)
{
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
Logging logger = Logging.GetLogger();
Type type = ((object)original).GetType();
logger.Debug($"Original Type is {type}");
GameObject obj = destination;
logger.Debug("Destination GameObject " + ((obj != null) ? ((Object)obj).name : null));
Component val = destination.GetComponent(type);
if ((Object)(object)val == (Object)null)
{
val = destination.AddComponent(type);
}
if ((Object)(object)val == (Object)null)
{
logger.Debug("Destination component is null");
return false;
}
Component val2 = (Component)Activator.CreateInstance(type);
if ((Object)(object)val2 == (Object)null)
{
logger.Debug("Destination component is null");
return false;
}
if ((Object)(object)val2 == (Object)null)
{
logger.Debug("Boxed component is null");
return false;
}
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
fieldInfo.SetValue(val2, fieldInfo.GetValue(original));
}
val = val2;
return true;
}
public static bool CopyObject(object original, object target)
{
Logging logger = Logging.GetLogger();
Type type = original.GetType();
Type type2 = target.GetType();
if (type == null)
{
logger.Warning("Copy Object: Source object is null");
Activator.CreateInstance(type);
return false;
}
if (type2 == null)
{
logger.Warning("Copy Object: Destination object is null");
return false;
}
if (type2 != type)
{
logger.Warning("Copy Object: Source and destination components are different types");
return false;
}
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
fieldInfo.SetValue(target, fieldInfo.GetValue(original));
}
return true;
}
}
internal class Cfg
{
public static DelegatedConfigEntry<Logging.LogLevels> debugLevel = null;
public static DelegatedConfigEntry<int> trophyCap = null;
public static DelegatedConfigEntry<int> damageCap = null;
public static DelegatedConfigEntry<int> trophyDistance = null;
public static DelegatedConfigEntry<bool> damagePhysical = null;
public static DelegatedConfigEntry<bool> damageElemental = null;
public static DelegatedConfigEntry<bool> damageOther = null;
public static DelegatedConfigEntry<SlayerSkills.Points> assignPoints = null;
public static DelegatedConfigEntry<bool> lowerSkillsOnDeath = null;
public static DelegatedConfigEntry<bool> allowCheats = null;
public static DelegatedConfigEntry<bool> useCreatureLevel = null;
public static DelegatedConfigEntry<int> bossPoints = null;
public static DelegatedConfigEntry<bool> tamesSlay = null;
public static DelegatedConfigEntry<bool> tamesBuff = null;
public static DelegatedConfigEntry<Color> skillColor = null;
private static KeyCode[] keyModifiers = (KeyCode[])(object)new KeyCode[2]
{
(KeyCode)308,
(KeyCode)304
};
public static KeyboardShortcut keyConfigItemDefault = new KeyboardShortcut((KeyCode)115, keyModifiers);
public static void BepInExConfig(BaseUnityPlugin _instance)
{
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Expected O, but got Unknown
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01b7: Expected O, but got Unknown
//IL_02df: Unknown result type (might be due to invalid IL or missing references)
//IL_02e9: Expected O, but got Unknown
debugLevel = new DelegatedConfigEntry<Logging.LogLevels>(SlayerSkills.ChangeLogging);
debugLevel.ConfigEntry = _instance.Config.Bind<Logging.LogLevels>("Utility", "LogLevel", Logging.LogLevels.Info, "Controls the level of information contained in the log");
SlayerSkills.Log.LogLevel = debugLevel.Value;
skillColor = new DelegatedConfigEntry<Color>(SlayerSkills.ChangeColor);
skillColor.ConfigEntry = _instance.Config.Bind<Color>("Utility", "SkillTextColor", Color.cyan, "Sets the color for the Slayer Skill text in the Trophy panel.");
trophyCap = new DelegatedConfigEntry<int>(useServerDelegate: true);
trophyCap.ConfigEntry = _instance.Config.Bind<int>("Slayer Skills", "SkillCap", 100, new ConfigDescription("Sets the maximum Slayer level attainable. Every slayer point earned increases the percentage of the damage buff against a specific creature type.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), Array.Empty<object>()));
trophyDistance = new DelegatedConfigEntry<int>(useServerDelegate: true);
trophyDistance.ConfigEntry = _instance.Config.Bind<int>("Slayer Skills", "TrophyDistance", 30, new ConfigDescription("Sets the maximum distance, in meters, that a player (in multiplayer) can be from the trophy drop to qualify for the trophy point.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 50), Array.Empty<object>()));
lowerSkillsOnDeath = new DelegatedConfigEntry<bool>(useServerDelegate: true);
lowerSkillsOnDeath.ConfigEntry = _instance.Config.Bind<bool>("Slayer Skills", "LowerSkillsOnDeath", true, "If enabled, will lower slayer skills upon death (same % as standard skills)");
allowCheats = new DelegatedConfigEntry<bool>(useServerDelegate: true);
allowCheats.ConfigEntry = _instance.Config.Bind<bool>("Slayer Skills", "AllowCheats", false, "If enabled, allows raising and resetting Slayer skills using 'raiseskill' and 'resetskill' commands from the console, If the creature name contains spaces, use an underscore (_) instead of a space, e.g. 'raiseskill Greydwarf_brute 3'. Note creature name is case sensitive!");
damageCap = new DelegatedConfigEntry<int>(useServerDelegate: true);
damageCap.ConfigEntry = _instance.Config.Bind<int>("Slayer Damage", "DamagePercent", 100, new ConfigDescription("Sets the maximum damage buff percent of your normal damage. The applied buff percentage is determined by your current Slayer level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
damagePhysical = new DelegatedConfigEntry<bool>(useServerDelegate: true);
damagePhysical.ConfigEntry = _instance.Config.Bind<bool>("Slayer Damage", "BuffPhysical", true, "If enabled, applies slayer bonus to physical damage (slash, blunt, pierce)");
damageElemental = new DelegatedConfigEntry<bool>(useServerDelegate: true);
damageElemental.ConfigEntry = _instance.Config.Bind<bool>("Slayer Damage", "BuffElemental", false, "If enabled, applies slayer bonus to elemental damage (lightning, fire, frost)");
damageOther = new DelegatedConfigEntry<bool>(useServerDelegate: true);
damageOther.ConfigEntry = _instance.Config.Bind<bool>("Slayer Damage", "BuffOther", false, "If enabled, applies slayer bonus to other damage (poison, spirit)");
assignPoints = new DelegatedConfigEntry<SlayerSkills.Points>(useServerDelegate: true);
assignPoints.ConfigEntry = _instance.Config.Bind<SlayerSkills.Points>("Slayer Points", "MultiplayerPoints", SlayerSkills.Points.Random, "Controls how slayer skills are awarded in multiplayer. Random grants skill points to one player in group. All grants a skill point to every player in group. Distribute grants a fraction of a skill point evenly to every player in group.");
useCreatureLevel = new DelegatedConfigEntry<bool>(useServerDelegate: true);
useCreatureLevel.ConfigEntry = _instance.Config.Bind<bool>("Slayer Points", "UseCreatureLevel", false, "If enabled, adjusts the Slayer points awarded on trophy drop based on the level (number of 'Stars') of the creature slain");
bossPoints = new DelegatedConfigEntry<int>(useServerDelegate: true);
bossPoints.ConfigEntry = _instance.Config.Bind<int>("Slayer Points", "BossAdjustment", 3, new ConfigDescription("Adjusts Slayer points awarded to account for bosses. Equivalent to treating a boss as an 'X-Star' creature. Applies even if UseCreatureLevel is false (and adds if true).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>()));
tamesSlay = new DelegatedConfigEntry<bool>(useServerDelegate: true);
tamesSlay.ConfigEntry = _instance.Config.Bind<bool>("Tamed Creatures", "TamesCanSlay", true, "If enabled, trophy drops from creatures slain by your tamed creatires count toward your Slayer skill");
tamesBuff = new DelegatedConfigEntry<bool>(useServerDelegate: true);
tamesBuff.ConfigEntry = _instance.Config.Bind<bool>("Tamed Creatures", "TamesGetBuff", false, "If enabled, your tamed creatures also recieve your Slayer buff");
}
}
internal class CreatureInfo
{
public string Name { get; }
public bool Tamed { get; }
public bool Tapped { get; }
public bool Boss { get; }
public int Level { get; }
public bool DropsEnabled { get; }
public CreatureInfo(string name, bool tamed, bool tapped, bool boss, int level, bool dropsEnabled)
{
Name = name;
Tamed = tamed;
Tapped = tapped;
Boss = boss;
Level = level;
DropsEnabled = dropsEnabled;
}
}
internal class CustomDataWrapper
{
private Dictionary<string, string> playerData;
private CustomDataWrapper instance;
private Dictionary<string, string> Data { get; set; }
public CustomDataWrapper(Dictionary<string, string> sourceData, string keyPrefix)
{
CustomDataWrapper customDataWrapper = this;
playerData = sourceData;
Data = new Dictionary<string, string>();
sourceData.Keys.ToList().ForEach(delegate(string key)
{
if (key.StartsWith(keyPrefix))
{
customDataWrapper.Data.Add(key, sourceData[key]);
}
});
}
public void Add(string key, string value)
{
Data.Add(key, value);
playerData.Add(key, value);
}
public bool Remove(string key)
{
return Data.Remove(key) & playerData.Remove(key);
}
public void Set(string key, string value)
{
if (Data.ContainsKey(key))
{
Data[key] = value;
}
else
{
Data.Add(key, value);
}
if (playerData.ContainsKey(key))
{
playerData[key] = value;
}
else
{
playerData.Add(key, value);
}
}
public string Get(string key)
{
if (Data.ContainsKey(key))
{
return Data[key];
}
return null;
}
public bool ContainsKey(string key)
{
return Data.ContainsKey(key);
}
public void PreSaveSync()
{
foreach (KeyValuePair<string, string> datum in Data)
{
if (!playerData.ContainsKey(datum.Key))
{
playerData.Add(datum.Key, datum.Value);
}
}
}
}
[BepInPlugin("neobotics.valheim_mod.slayerskills", "SlayerSkills", "1.0.8")]
[BepInProcess("valheim.exe")]
[BepInProcess("valheim_server.exe")]
public class SlayerSkills : BaseUnityPlugin
{
public enum Points
{
Random,
All,
Distribute,
KillingBlow
}
[HarmonyPatch(typeof(Localization), "SetLanguage")]
private static class Localization_SetLanguage_Patch
{
[HarmonyPostfix]
private static void Localization_SetLanguage_Postfix(Localization __instance)
{
BuildCreatureTrophyMap();
}
}
[HarmonyPatch(typeof(Game), "Start")]
private static class Game_Start_Patch
{
[HarmonyPostfix]
private static void Game_Start_Patch_Postfix(Game __instance)
{
Log.Debug(" Game_Start_Patch_Postfix");
ZRoutedRpc.instance.Register<string, float>("RaiseSlayerStat", (Action<long, string, float>)RPC_RaiseSlayerStat);
}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
private static class ZNetScene_Awake_Patch
{
[HarmonyPostfix]
private static void ZNetScene_Awake_Postfix(ZNetScene __instance)
{
Log.Debug("ZNetScene_Awake_Patch_Postfix");
BuildCreatureTrophyMap();
}
}
[HarmonyPatch(typeof(InventoryGui), "UpdateTrophyList")]
private static class InventoryGui_UpdateTrophyList_Patch
{
[HarmonyPostfix]
private static void InventoryGui_UpdateTrophyList_Postfix(InventoryGui __instance, List<GameObject> ___m_trophyList)
{
Log.Debug("InventoryGui_UpdateTrophyList_Patch_Postfix");
if (___m_trophyList == null)
{
return;
}
foreach (GameObject ___m_trophy in ___m_trophyList)
{
Transform transform = ___m_trophy.transform;
Transform obj = ((transform is RectTransform) ? transform : null);
TMP_Text component = ((Component)obj.Find("description")).GetComponent<TMP_Text>();
TMP_Text component2 = ((Component)obj.Find("name")).GetComponent<TMP_Text>();
if (nameToTokenMap.TryGetValue(component2.text, out var value))
{
if (trophyCollection.TryGetValue(value, out var value2))
{
string text = ((value2 < (float)Cfg.trophyCap.Value) ? $"{FlooredLevel(value2)}/{Cfg.trophyCap.Value}" : "Slayer");
component.richText = true;
component.text = "<color=" + colorString + ">" + text + "</color>\n" + component.text;
}
else
{
Log.Debug("Can't find mapped token " + value + " in trophy collection");
}
}
else
{
Log.Debug("Can't find localized name " + component2.text + " slayerSkill");
}
}
}
}
[HarmonyPatch(typeof(CharacterDrop), "OnDeath")]
private static class CharacterDrop_OnDeath_Patch
{
[HarmonyPrefix]
private static void CharacterDrop_OnDeath_Prefix(CharacterDrop __instance, Character ___m_character)
{
Log.Debug("CharacterDrop_OnDeath_Patch_Prefix");
bool tapped = false;
ZNetView val = default(ZNetView);
if (((Component)___m_character).TryGetComponent<ZNetView>(ref val))
{
ZDO zDO = val.GetZDO();
if (zDO.IsValid() && zDO.GetBool(UNIQUE_ID, false))
{
tapped = true;
}
}
if ((Object)(object)___m_character != (Object)null)
{
_tempCreatureInfo = new CreatureInfo(___m_character.m_name, ___m_character.IsTamed(), tapped, ___m_character.IsBoss(), ___m_character.GetLevel(), __instance.m_dropsEnabled);
}
}
[HarmonyPostfix]
private static void CharacterDrop_OnDeath_Postfix(CharacterDrop __instance, ref CreatureInfo __state)
{
Log.Debug("CharacterDrop_OnDeath_Patch_Postfix");
_tempCreatureInfo = null;
}
}
[HarmonyPatch(typeof(CharacterDrop), "DropItems")]
private static class CharacterDrop_DropItems_Patch
{
[HarmonyPostfix]
private static void CharacterDrop_DropItems_Postfix(List<KeyValuePair<GameObject, int>> drops, Vector3 centerPos, float dropArea, bool ___m_dropsEnabled)
{
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Invalid comparison between Unknown and I4
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
Log.Debug("CharacterDrop_DropItems_Patch_Postfix");
if (_tempCreatureInfo == null || _tempCreatureInfo.Tamed || !_tempCreatureInfo.DropsEnabled)
{
return;
}
if (_tempCreatureInfo.Tapped)
{
Log.Debug("Creature was tapped by a player");
{
ItemDrop val = default(ItemDrop);
foreach (KeyValuePair<GameObject, int> drop in drops)
{
if ((Object)(object)drop.Key != (Object)null && drop.Key.TryGetComponent<ItemDrop>(ref val) && (int)val.m_itemData.m_shared.m_itemType == 13)
{
int num = ((!Cfg.useCreatureLevel.Value) ? 1 : _tempCreatureInfo.Level);
if (_tempCreatureInfo.Boss)
{
num += Cfg.bossPoints.Value;
}
InitiateRaiseStat(val.m_itemData.m_shared.m_name, num, centerPos);
}
}
return;
}
}
Log.Debug("Character " + _tempCreatureInfo.Name + " was not hit by player");
}
}
[HarmonyPatch(typeof(Ragdoll), "SaveLootList")]
private static class Ragdoll_SaveLootList_Patch
{
[HarmonyPostfix]
private static void Ragdoll_SaveLootList_Postfix(Ragdoll __instance, CharacterDrop characterDrop, ZNetView ___m_nview)
{
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Invalid comparison between Unknown and I4
Log.Debug("Ragdoll_SaveLootList_Patch_Postfix");
Character character = characterDrop.m_character;
ZNetView val = default(ZNetView);
if (!((Object)(object)character != (Object)null) || character.IsTamed() || !((Component)character).TryGetComponent<ZNetView>(ref val))
{
return;
}
ZDO zDO = val.GetZDO();
if (zDO.IsValid() && zDO.GetBool(UNIQUE_ID, false))
{
ZDO zDO2 = ___m_nview.GetZDO();
Log.Debug("Creature was tapped by a player");
int @int = zDO2.GetInt("drops", 0);
ItemDrop val2 = default(ItemDrop);
for (int i = 0; i < @int; i++)
{
int int2 = zDO2.GetInt("drop_hash" + i, 0);
GameObject prefab = ZNetScene.instance.GetPrefab(int2);
if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent<ItemDrop>(ref val2) && (int)val2.m_itemData.m_shared.m_itemType == 13)
{
int num = ((!Cfg.useCreatureLevel.Value) ? 1 : character.GetLevel());
if (character.IsBoss())
{
num += Cfg.bossPoints.Value;
}
string text = $"{val2.m_itemData.m_shared.m_name}:{num}";
Log.Debug("Setting ragdoll with " + text);
if (zDO2.IsValid())
{
zDO2.Set(StringExtensionMethods.GetStableHashCode(UNIQUE_ID), text);
}
}
}
}
else
{
Log.Debug("Character " + ((character != null) ? ((Object)character).name : null) + " was not hit by player");
}
}
}
[HarmonyPatch(typeof(Ragdoll), "SpawnLoot")]
private static class Ragdoll_SpawnLoot_Patch
{
[HarmonyPostfix]
private static void Ragdoll_SpawnLoot_Postfix(Ragdoll __instance, Vector3 center, ZNetView ___m_nview)
{
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
Log.Debug("Ragdoll_SpawnLoot_Patch_Postfix");
string text = null;
ZDO zDO = ___m_nview.GetZDO();
if (zDO.IsValid())
{
text = zDO.GetString(StringExtensionMethods.GetStableHashCode(UNIQUE_ID), "");
}
if (!Utility.IsNullOrWhiteSpace(text))
{
string[] array = text.Split(new char[1] { ':' });
string itemName = array[0];
float amount = float.Parse(array[1]);
Log.Debug("Ragdoll is spawning trophy");
InitiateRaiseStat(itemName, amount, center);
}
}
}
[HarmonyPatch(typeof(Character), "Damage")]
private static class Character_Damage_Patch
{
[HarmonyPrefix]
private static void Character_Damage_Prefix(Character __instance, ref HitData hit, ZNetView ___m_nview)
{
Log.Debug("Character_Damage_Patch_Prefix");
Collider hitCollider = hit.m_hitCollider;
Character attacker = hit.GetAttacker();
Player localPlayer = Player.m_localPlayer;
if (!((Object)(object)attacker != (Object)null) || !((Object)(object)localPlayer != (Object)null) || __instance.IsPlayer())
{
return;
}
ZDO zDO = ((Component)attacker).GetComponent<ZNetView>().GetZDO();
bool @bool = zDO.GetBool("tamed", false);
bool flag = @bool && zDO.GetOwner() == localPlayer.GetPlayerID();
if ((Object)(object)attacker == (Object)(object)localPlayer || (flag && Cfg.tamesBuff.Value))
{
object name;
if (hitCollider == null)
{
name = null;
}
else
{
Transform transform = ((Component)hitCollider).transform;
if (transform == null)
{
name = null;
}
else
{
Transform root = transform.root;
name = ((root != null) ? ((Object)root).name : null);
}
}
string text = Utils.UnClonifiedName((string)name);
if (Utility.IsNullOrWhiteSpace(text))
{
Logging log = Log;
object obj;
if (hitCollider == null)
{
obj = null;
}
else
{
Transform transform2 = ((Component)hitCollider).transform;
if (transform2 == null)
{
obj = null;
}
else
{
Transform root2 = transform2.root;
obj = ((root2 != null) ? ((Object)root2).name : null);
}
}
log.Info("Can't determine original name " + (string?)obj);
return;
}
Log.Debug(((attacker != null) ? attacker.GetHoverName() : null) + " hit " + text);
if (creatureTrophyMap.TryGetValue(text, out var value))
{
if (trophyCollection.TryGetValue(value, out var value2))
{
ApplySlayerBonus(ref hit, Mathf.Min(value2, (float)Cfg.trophyCap.Value));
}
else
{
Log.Debug("Can't find " + value + " in trophy collection");
}
}
else
{
Log.Debug("Can't find hit original " + text + " slayerSkill");
}
}
if (attacker.IsPlayer() || (@bool && Cfg.tamesSlay.Value))
{
Log.Debug("Player tapping original");
ZDO zDO2 = ___m_nview.GetZDO();
zDO2.Set(UNIQUE_ID, true);
zDO2.SetOwner(attacker.GetOwner());
}
}
}
[HarmonyPatch(typeof(Player), "Save")]
public static class Player_Save_Patch
{
[HarmonyPrefix]
public static void Player_Save_Patch_Prefix(Player __instance, ZPackage pkg)
{
Log.Debug("Player_Save_Patch_Prefix");
if (customData != null)
{
string text = Utils.SerializeFromDictionary(",", ":", trophyCollection);
customData.Set(COLLECTION_ID, text);
Log.Debug("Serializing and adding trophy collection " + text);
customData.PreSaveSync();
}
}
}
[HarmonyPatch(typeof(Player), "OnSpawned")]
public static class Player_OnSpawned_Patch
{
[HarmonyPostfix]
public static void Player_OnSpawned_Patch_Postfix(Player __instance)
{
Log.Debug("Player_OnSpawned_Patch_Postfix");
if (ZNet.m_world == null)
{
return;
}
customData = new CustomDataWrapper(__instance.m_customData, UNIQUE_ID);
string text = customData.Get(COLLECTION_ID);
if (text != null)
{
Utils.DeserializeToDictionary(text, ",", ":", ref trophyCollection);
Log.Debug("Deserialized trophy string " + text);
}
if (trophyCollection.Count <= 0 || trophyCollection.Keys.First().StartsWith("$"))
{
return;
}
Log.Info("Remapping trophy collection to newer version");
Dictionary<string, float> dictionary = new Dictionary<string, float>();
Dictionary<string, string> dictionary2 = new Dictionary<string, string>
{
{ "Greydwarf Brute", "Greydwarf brute" },
{ "Greydwarf Shamen", "Greydwarf shamen" },
{ "Draugr Elite", "Drauger elite" }
};
List<string> list = new List<string>();
foreach (string key2 in dictionary2.Keys)
{
if (trophyCollection.TryGetValue(key2, out var value))
{
string key = dictionary2[key2];
if (trophyCollection.ContainsKey(key))
{
trophyCollection[key] += value;
}
else
{
trophyCollection.Add(key, value);
}
list.Add(key2);
}
}
foreach (string item in list)
{
trophyCollection.Remove(item);
}
foreach (string key3 in trophyCollection.Keys)
{
Log.Debug("Remapping " + key3);
if (nameToTokenMap.TryGetValue(key3, out var value2))
{
Log.Debug("Found " + key3 + " with new key " + value2 + " from name-to-token map");
dictionary.Add(value2, trophyCollection[key3]);
}
else
{
Log.Debug("Couldn't find " + key3 + " in name-to-token map");
}
}
trophyCollection = dictionary;
text = Utils.SerializeFromDictionary(",", ":", trophyCollection);
Log.Debug("New trophy string " + text);
}
}
[HarmonyPatch(typeof(Skills), "LowerAllSkills")]
private static class Skills_LowerAllSkills_Patch
{
[HarmonyPostfix]
private static void Skills_LowerAllSkills_Postfix(Skills __instance, float factor)
{
Log.Debug("Skills_LowerAllSkills_Patch_Postfix");
if (!Cfg.lowerSkillsOnDeath.Value)
{
return;
}
foreach (string item in trophyCollection.Keys.ToList())
{
if (trophyCollection[item] < (float)Cfg.trophyCap.Value)
{
float num = trophyCollection[item] * factor;
trophyCollection[item] -= num;
}
}
}
}
[HarmonyPatch(typeof(Skills), "CheatRaiseSkill")]
private static class Skills_CheatRaiseSkill_Patch
{
private static bool Prefix(string name, float value)
{
Logging.GetLogger().Debug("Skills CheatRaiseSkill Prefix");
if (Cfg.allowCheats.Value)
{
name = name.Replace('_', ' ');
if (nameToTokenMap.TryGetValue(name, out var value2) && trophyCollection.TryGetValue(value2, out var value3))
{
value3 += value;
value3 = Mathf.Clamp(value3, 0f, (float)Cfg.trophyCap.Value);
trophyCollection[value2] = value3;
Console.instance.Print($"Slayer skill {name} = {value3}");
return false;
}
}
else
{
Log.Debug("SlayerSkills cheats are not enabled");
}
return true;
}
}
[HarmonyPatch(typeof(Skills), "CheatResetSkill")]
private static class Skills_CheatResetSkill_Patch
{
private static bool Prefix(string name)
{
Logging.GetLogger().Debug("Skills CheatResetSkill Prefix");
if (Cfg.allowCheats.Value)
{
name = name.Replace('_', ' ');
if (nameToTokenMap.TryGetValue(name, out var value) && trophyCollection.ContainsKey(value))
{
trophyCollection[value] = 0f;
Console.instance.Print("Slayer skill " + name + " reset");
return false;
}
}
else
{
Log.Debug("SlayerSkills cheats are not enabled");
}
return true;
}
}
[HarmonyPatch(typeof(Terminal), "TryRunCommand")]
private static class Try_Run_Command_Patch
{
private static void Prefix(Terminal __instance, ref string text)
{
if (text == null)
{
return;
}
string text2 = text.ToLower();
if (!text2.StartsWith(LcMod))
{
return;
}
string text3 = text2.Substring(LcMod.Length + 1).Trim();
Log.Debug(Mod + " Configuration command: " + text3);
if (text3.Equals("config"))
{
((BaseUnityPlugin)_modInstance).Config.Reload();
_modInstance.ConfigureMod();
__instance.AddString("Reset configuration");
}
else
{
string[] array = text3.Split(new string[1] { "=" }, 2, StringSplitOptions.RemoveEmptyEntries);
if (array.Length == 2)
{
string text4 = array[0].Trim();
string text5 = array[1].Trim();
bool flag = true;
switch (text4)
{
case "loglevel":
{
if (Enum.TryParse<Logging.LogLevels>(text5, out var result5))
{
Cfg.debugLevel.Value = result5;
}
else
{
flag = false;
}
break;
}
case "skillcap":
{
if (int.TryParse(text5, out var result3))
{
Cfg.trophyCap.Value = Utils.Guardrails(result3, 1, 200);
}
else
{
flag = false;
}
break;
}
case "damagepercent":
{
if (int.TryParse(text5, out var result6))
{
Cfg.damageCap.Value = Utils.Guardrails(result6, 0, 100);
}
else
{
flag = false;
}
break;
}
case "trophydistance":
{
if (int.TryParse(text5, out var result2))
{
Cfg.trophyDistance.Value = Utils.Guardrails(result2, 5, 50);
}
else
{
flag = false;
}
break;
}
case "buffphysical":
Cfg.damagePhysical.ConfigEntry.Value = text5.Equals("true");
break;
case "lowerskillsondeath":
Cfg.lowerSkillsOnDeath.ConfigEntry.Value = text5.Equals("true");
break;
case "buffelemental":
Cfg.damageElemental.ConfigEntry.Value = text5.Equals("true");
break;
case "buffother":
Cfg.damageOther.ConfigEntry.Value = text5.Equals("true");
break;
case "multiplayerpoints":
{
if (Enum.TryParse<Points>(text5, out var result4))
{
Cfg.assignPoints.Value = result4;
}
else
{
flag = false;
}
break;
}
case "bossadjustment":
{
if (int.TryParse(text5, out var result))
{
Cfg.bossPoints.Value = Utils.Guardrails(result, 0, 10);
}
else
{
flag = false;
}
break;
}
case "usecreaturelevel":
Cfg.useCreatureLevel.ConfigEntry.Value = text5.Equals("true");
break;
case "tamescanslay":
Cfg.tamesSlay.ConfigEntry.Value = text5.Equals("true");
break;
case "tamesgetbuff":
Cfg.tamesBuff.ConfigEntry.Value = text5.Equals("true");
break;
case "allowcheats":
Cfg.allowCheats.ConfigEntry.Value = text5.Equals("true");
break;
default:
flag = false;
break;
}
if (flag)
{
__instance.AddString("Reset " + text4 + "=" + text5);
}
else
{
__instance.AddString("Not a valid setting");
}
}
else
{
__instance.AddString("Not a valid command");
}
}
text = "";
}
}
private static SlayerSkills _modInstance;
private const string MOD_VERSION = "1.0.8";
private static string Mod = "SlayerSkills";
private static string LcMod = Mod.ToLower();
public static Logging Log;
public static string UNIQUE_ID = Mod + "_1847_";
public static string COLLECTION_ID = UNIQUE_ID + "_C";
private static CustomDataWrapper customData = null;
private static IDictionary<string, float> trophyCollection = new Dictionary<string, float>();
private static IDictionary<string, string> creatureTrophyMap = new Dictionary<string, string>();
private static IDictionary<string, string> nameToTokenMap = new Dictionary<string, string>();
private static CreatureInfo _tempCreatureInfo = null;
private static string colorString = "#00FFFF";
private static Harmony harmony = null;
public static SlayerSkills GetInstance()
{
return _modInstance;
}
private void Awake()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
_modInstance = this;
harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
harmony.PatchAll(Assembly.GetExecutingAssembly());
ConfigureMod();
Log.Info("Awake");
}
private void ConfigureMod()
{
Log = Logging.GetLogger(Logging.LogLevels.Info, Mod);
ServerConfiguration.Instance.Setup(((BaseUnityPlugin)this).Config, (BaseUnityPlugin)(object)_modInstance);
Cfg.BepInExConfig((BaseUnityPlugin)(object)_modInstance);
}
public static void ChangeLogging(object s, EventArgs e)
{
SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null);
Log.Debug($"ChangeLog {val.ChangedSetting.Definition.Key} to {val.ChangedSetting.BoxedValue}");
Log.LogLevel = Cfg.debugLevel.Value;
}
public static void ChangeColor(object s, EventArgs e)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null);
Log.Debug($"ChangeColor {val.ChangedSetting.Definition.Key} to {val.ChangedSetting.BoxedValue}");
colorString = "#" + ColorUtility.ToHtmlStringRGB(Cfg.skillColor.Value);
}
private void OnDestroy()
{
harmony.UnpatchSelf();
}
private static int GetVersionID(string versionString)
{
string[] array = versionString.Split(new char[1] { '.' });
return int.Parse(array[0]) * 10000 + int.Parse(array[1]) * 1000 + int.Parse(array[2]);
}
private static bool OkToKey(Player player)
{
if (!Chat.instance.HasFocus() && !Console.IsVisible() && (Object)(object)TextViewer.instance != (Object)null && !TextViewer.instance.IsVisible() && !GameCamera.InFreeFly() && !Minimap.IsOpen() && !TextInput.IsVisible() && !StoreGui.IsVisible() && !((Character)player).InCutscene() && !((Character)player).InBed() && !((Character)player).IsTeleporting() && !((Character)player).IsDead())
{
return !((Character)player).InPlaceMode();
}
return false;
}
private static void KeypressEntryPoint()
{
_ = Player.m_localPlayer;
Log.Debug("KeypressEntryPoint");
}
private static string GetTrophyDisplayName(string trophyName)
{
string text = Localization.instance.Localize(trophyName);
if (!text.EndsWith(" trophy"))
{
return text;
}
return text.Substring(0, text.Length - 7);
}
private static void ApplySlayerBonus(ref HitData hitData, float skillLevel)
{
skillLevel = Mathf.Clamp(skillLevel, 0f, (float)Cfg.trophyCap.Value);
float num = skillLevel / (float)Cfg.trophyCap.Value;
float num2 = (float)Cfg.damageCap.Value / 100f * num;
Log.Debug($"Before slayer Level {skillLevel} multiplier {num2} blunt {hitData.m_damage.m_blunt} slash {hitData.m_damage.m_slash} pierce {hitData.m_damage.m_pierce} fire {hitData.m_damage.m_fire} frost {hitData.m_damage.m_frost} lightning {hitData.m_damage.m_lightning} poison {hitData.m_damage.m_poison} spirit {hitData.m_damage.m_spirit}");
if (Cfg.damagePhysical.Value)
{
hitData.m_damage.m_blunt += hitData.m_damage.m_blunt * num2;
hitData.m_damage.m_slash += hitData.m_damage.m_slash * num2;
hitData.m_damage.m_pierce += hitData.m_damage.m_pierce * num2;
}
if (Cfg.damageElemental.Value)
{
hitData.m_damage.m_fire += hitData.m_damage.m_fire * num2;
hitData.m_damage.m_frost += hitData.m_damage.m_frost * num2;
hitData.m_damage.m_lightning += hitData.m_damage.m_lightning * num2;
}
if (Cfg.damageOther.Value)
{
hitData.m_damage.m_spirit += hitData.m_damage.m_spirit * num2;
hitData.m_damage.m_poison += hitData.m_damage.m_poison * num2;
}
Log.Debug($"After slayer Level {skillLevel} multiplier {num2} blunt {hitData.m_damage.m_blunt} slash {hitData.m_damage.m_slash} pierce {hitData.m_damage.m_pierce} fire {hitData.m_damage.m_fire} frost {hitData.m_damage.m_frost} lightning {hitData.m_damage.m_lightning} poison {hitData.m_damage.m_poison} spirit {hitData.m_damage.m_spirit}");
}
public static void BuildCreatureTrophyMap()
{
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Invalid comparison between Unknown and I4
CharacterDrop val = default(CharacterDrop);
ItemDrop val2 = default(ItemDrop);
foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
{
Character component = (Character)(object)prefab.GetComponent<Humanoid>();
if ((Object)(object)component == (Object)null)
{
component = prefab.GetComponent<Character>();
}
if (!((Object)(object)component != (Object)null) || !prefab.TryGetComponent<CharacterDrop>(ref val))
{
continue;
}
foreach (Drop drop in val.m_drops)
{
if ((Object)(object)drop.m_prefab != (Object)null && drop.m_prefab.TryGetComponent<ItemDrop>(ref val2) && (int)val2.m_itemData.m_shared.m_itemType == 13)
{
string name = val2.m_itemData.m_shared.m_name;
string trophyDisplayName = GetTrophyDisplayName(name);
if (!creatureTrophyMap.ContainsKey(((Object)component).name))
{
Log.Debug("Adding " + ((Object)component).name + " " + name + " to original trophy map");
creatureTrophyMap.Add(((Object)component).name, name);
}
if (!nameToTokenMap.ContainsKey(trophyDisplayName))
{
Log.Debug("Adding " + trophyDisplayName + " " + name + " to name-to-token map");
nameToTokenMap.Add(trophyDisplayName, name);
}
}
}
}
}
private static int FlooredLevel(float level)
{
return Mathf.FloorToInt(level);
}
private static void RaiseStat(string itemName, float amt)
{
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
Log.Debug("RaiseStat");
bool flag = false;
string trophyDisplayName = GetTrophyDisplayName(itemName);
Log.Debug(itemName + " translates to trophy name " + trophyDisplayName);
if (!trophyCollection.ContainsKey(itemName))
{
trophyCollection.Add(itemName, amt);
int num = FlooredLevel(amt);
if (num >= 1)
{
((Character)Player.m_localPlayer).Message((MessageType)2, $"{trophyDisplayName} Slayer Level {num}", 0, (Sprite)null);
flag = true;
}
Log.Debug("Adding " + trophyDisplayName + " to slayer collection");
}
else
{
int num2 = FlooredLevel(trophyCollection[itemName]);
if (num2 < Cfg.trophyCap.Value)
{
trophyCollection[itemName] += amt;
if (trophyCollection[itemName] > (float)Cfg.trophyCap.Value)
{
trophyCollection[itemName] = Cfg.trophyCap.Value;
}
int num3 = FlooredLevel(trophyCollection[itemName]);
if (num3 > num2)
{
((Character)Player.m_localPlayer).Message((MessageType)1, $"{trophyDisplayName} Slayer Level {num3}", 0, (Sprite)null);
flag = true;
}
}
else
{
Log.Debug("Trophy cap reached");
}
}
if (flag)
{
Player localPlayer = Player.m_localPlayer;
Transform head = ((Character)localPlayer).m_head;
localPlayer.m_skillLevelupEffects.Create(head.position, head.rotation, head, 1f, -1);
}
}
private static void RPC_RaiseSlayerStat(long id, string itemName, float amt)
{
Log.Debug("RPC_RaiseSlayerStat");
RaiseStat(itemName, amt);
}
private static List<Player> GetPlayersInRange(Vector3 point, float range, List<Player> allPlayers)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
List<Player> list = new List<Player>();
foreach (Player allPlayer in allPlayers)
{
if (Vector3.Distance(((Component)allPlayer).transform.position, point) < range)
{
list.Add(allPlayer);
}
}
return list;
}
private static void InitiateRaiseStat(string itemName, float amount, Vector3 center)
{
//IL_0033: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
Log.Debug("IntitiateRaiseStat");
List<Player> allPlayers = Player.GetAllPlayers();
int num = allPlayers.Count();
if (num > 1 && Cfg.assignPoints.Value != Points.KillingBlow)
{
List<Player> playersInRange = GetPlayersInRange(center, Cfg.trophyDistance.Value, allPlayers);
Log.Debug($"Players in range {playersInRange.Count}");
if (playersInRange.Count < num)
{
Log.Info($"{num - playersInRange.Count} player(s) not in range of the dropped trophy.");
}
if (playersInRange.Count <= 0)
{
return;
}
if (Cfg.assignPoints.Value != 0)
{
if (Cfg.assignPoints.Value == Points.Distribute)
{
amount /= (float)playersInRange.Count;
}
{
ZNetView val = default(ZNetView);
foreach (Player item in playersInRange)
{
if (((Component)item).TryGetComponent<ZNetView>(ref val) && val.IsValid() && val.GetZDO().m_uid != ZDOID.None)
{
Log.Debug($"Invoking RPC on {val.GetZDO().GetOwner()} player {item.GetPlayerName()}");
ZRoutedRpc.instance.InvokeRoutedRPC(val.GetZDO().GetOwner(), "RaiseSlayerStat", new object[2] { itemName, amount });
}
}
return;
}
}
int index = Random.Range(0, playersInRange.Count);
ZNetView val2 = default(ZNetView);
if (((Component)playersInRange[index]).TryGetComponent<ZNetView>(ref val2) && val2.IsValid() && val2.GetZDO().m_uid != ZDOID.None)
{
Log.Debug($"Invoking RPC on {val2.GetZDO().GetOwner()} random player {playersInRange[index].GetPlayerName()}");
ZRoutedRpc.instance.InvokeRoutedRPC(val2.GetZDO().GetOwner(), "RaiseSlayerStat", new object[2] { itemName, amount });
}
}
else
{
RaiseStat(itemName, amount);
}
}
}