using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NoUnarmedCombat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Riintouge")]
[assembly: AssemblyProduct("No Unarmed Combat")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6245a6e2-549d-4d09-b596-43a8169cad43")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.2.0")]
namespace NoUnarmedCombat;
[BepInPlugin("com.riintouge.nounarmedcombat", "No Unarmed Combat", "1.0.2")]
[BepInProcess("valheim.exe")]
public class NoUnarmedCombat : BaseUnityPlugin
{
[HarmonyPatch(typeof(Humanoid))]
private class HumanoidPatch
{
private static bool InStartAttack;
private static bool PerformingSecondaryAttack;
private static bool SheathedBecauseSwimming;
private static bool SkipNextEquipAttempt;
private static ItemData[] GetToolbarWeaponsAndShield(Humanoid humanoid)
{
List<ItemData> list = new List<ItemData>();
humanoid.GetInventory().GetBoundItems(list);
List<ItemData> source = (from x in list
orderby x.m_gridPos.x
where x.GetDurabilityPercentage() > 0f
select x).ToList();
return (ItemData[])(object)new ItemData[3]
{
((IEnumerable<ItemData>)source).FirstOrDefault((Func<ItemData, bool>)((ItemData itemData) => itemData.IsWeapon() && itemData.IsTwoHanded())),
((IEnumerable<ItemData>)source).FirstOrDefault((Func<ItemData, bool>)((ItemData itemData) => itemData.IsWeapon() && !itemData.IsTwoHanded())),
((IEnumerable<ItemData>)source).FirstOrDefault((Func<ItemData, bool>)((ItemData itemData) => ItemIsShield(itemData)))
};
}
private static bool HumanoidIsLocalPlayer(Humanoid humanoid)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (((Character)humanoid).IsPlayer())
{
ZDOID zDOID = ((Character)humanoid).GetZDOID();
return ((ZDOID)(ref zDOID)).UserID == ZDOMan.GetSessionID();
}
return false;
}
private static bool ItemIsShield(ItemData itemData)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Invalid comparison between Unknown and I4
if (itemData == null)
{
return false;
}
return (int)itemData.m_shared.m_itemType == 5;
}
private static void ShowHandItems(ref Humanoid __instance)
{
Traverse.Create((object)__instance).Method("ShowHandItems", Array.Empty<object>()).GetValue();
}
[HarmonyPatch("GetCurrentWeapon")]
[HarmonyPostfix]
private static ItemData GetCurrentWeaponPostfix(ItemData result, ref Humanoid __instance, ref ItemData ___m_hiddenLeftItem, ref ItemData ___m_hiddenRightItem)
{
if (InStartAttack && IsEnabled.Value && result == __instance.m_unarmedWeapon?.m_itemData && HumanoidIsLocalPlayer(__instance) && (!PerformingSecondaryAttack || !AllowKick.Value))
{
if (UnsheatheOnPunch.Value && (___m_hiddenLeftItem != null || ___m_hiddenRightItem != null))
{
return null;
}
if (ToolbarEquipOnPunch.Value)
{
ItemData[] toolbarWeaponsAndShield = GetToolbarWeaponsAndShield(__instance);
if (toolbarWeaponsAndShield[0] != null || toolbarWeaponsAndShield[1] != null)
{
return null;
}
}
if (!FallbackFisticuffs.Value)
{
SkipNextEquipAttempt = true;
return null;
}
}
return result;
}
[HarmonyPatch("StartAttack")]
[HarmonyPrefix]
private static bool StartAttackPrefix(ref Humanoid __instance, ref bool secondaryAttack)
{
if (!IsEnabled.Value)
{
return true;
}
if (HumanoidIsLocalPlayer(__instance) && Minimap.IsOpen())
{
return false;
}
InStartAttack = true;
PerformingSecondaryAttack = secondaryAttack;
return true;
}
[HarmonyPatch("StartAttack")]
[HarmonyPostfix]
private static void StartAttackPostfix(ref Humanoid __instance, ref ItemData ___m_hiddenLeftItem, ref ItemData ___m_hiddenRightItem, ref ZSyncAnimation ___m_zanim)
{
bool num = !IsEnabled.Value || !HumanoidIsLocalPlayer(__instance) || __instance.GetCurrentWeapon() != null || !InStartAttack || SkipNextEquipAttempt;
InStartAttack = false;
PerformingSecondaryAttack = false;
SkipNextEquipAttempt = false;
if (num)
{
return;
}
ItemData val = __instance.RightItem;
ItemData val2 = __instance.LeftItem;
if (val != null || val2 != null)
{
return;
}
ItemData val3 = null;
ItemData val4 = null;
if (UnsheatheOnPunch.Value && (___m_hiddenRightItem != null || ___m_hiddenLeftItem != null))
{
if (!ToolbarEquipOnPunch.Value || (___m_hiddenLeftItem != null && ___m_hiddenRightItem != null))
{
ShowHandItems(ref __instance);
return;
}
val = ___m_hiddenRightItem;
val2 = ___m_hiddenLeftItem;
val3 = ___m_hiddenRightItem;
val4 = ___m_hiddenLeftItem;
}
if (!ToolbarEquipOnPunch.Value || (val3 != null && val4 != null))
{
return;
}
ItemData[] toolbarWeaponsAndShield = GetToolbarWeaponsAndShield(__instance);
ItemData val5 = toolbarWeaponsAndShield[0];
ItemData val6 = toolbarWeaponsAndShield[1];
ItemData val7 = toolbarWeaponsAndShield[2];
if (val3 == null && val4 == null)
{
if (val6 != null && val5 != null)
{
if (val6.m_gridPos.x < val5.m_gridPos.x)
{
val3 = val6;
val4 = val7;
}
else
{
val3 = val5;
}
}
else if (val5 != null)
{
val3 = val5;
}
else
{
val3 = val6;
val4 = val7;
}
}
else if (val3 != null && val4 == null)
{
if (!val3.IsTwoHanded())
{
val4 = val7;
}
}
else if (val3 == null && val4 != null && !val4.IsTwoHanded() && !val4.IsWeapon() && ItemIsShield(val4) && val6 != null)
{
val3 = val6;
}
if (val != null)
{
__instance.EquipItem(val, true);
}
else if (val3 != null && !__instance.IsItemEquiped(val3))
{
__instance.EquipItem(val3, true);
val = val3;
}
if (val2 != null)
{
__instance.EquipItem(val2, true);
}
else if (val4 != null && !__instance.IsItemEquiped(val4))
{
__instance.EquipItem(val4, true);
if (val != null && !__instance.IsItemEquiped(val))
{
__instance.EquipItem(val, true);
}
else
{
val2 = val4;
}
}
if (val != null || val2 != null)
{
___m_zanim.SetTrigger("equip_hip");
}
PlayerPatch.RestoreQueuedAttackTimers = true;
}
[HarmonyPatch("UpdateEquipment")]
[HarmonyPrefix]
private static void UpdateEquipmentPrefix(ref Humanoid __instance, ref ItemData ___m_leftItem, ref ItemData ___m_rightItem)
{
if (!HumanoidIsLocalPlayer(__instance))
{
return;
}
if (((Character)__instance).IsSwimming() && !((Character)__instance).IsOnGround())
{
SheathedBecauseSwimming |= ___m_leftItem != null || ___m_rightItem != null;
}
else if (SheathedBecauseSwimming)
{
if (IsEnabled.Value && UnsheatheAfterSwimming.Value)
{
ShowHandItems(ref __instance);
}
SheathedBecauseSwimming = false;
}
}
}
[HarmonyPatch(typeof(Player))]
private class PlayerPatch
{
internal static bool RestoreQueuedAttackTimers;
private static float LastAttackTimer;
private static float LastSecondaryAttackTimer;
[HarmonyPatch("PlayerAttackInput")]
[HarmonyPrefix]
private static void PlayerAttackInputPrefix(ref float ___m_queuedAttackTimer, ref float ___m_queuedSecondAttackTimer)
{
LastAttackTimer = ___m_queuedAttackTimer;
LastSecondaryAttackTimer = ___m_queuedSecondAttackTimer;
}
[HarmonyPatch("PlayerAttackInput")]
[HarmonyPostfix]
private static void PlayerAttackInputPostfix(ref float ___m_queuedAttackTimer, ref float ___m_queuedSecondAttackTimer)
{
if (RestoreQueuedAttackTimers)
{
___m_queuedAttackTimer = LastAttackTimer;
___m_queuedSecondAttackTimer = LastSecondaryAttackTimer;
}
}
}
public static ConfigEntry<bool> IsEnabled;
public static ConfigEntry<bool> LoadOnStart;
public static ConfigEntry<bool> AllowKick;
public static ConfigEntry<bool> FallbackFisticuffs;
public static ConfigEntry<bool> ToolbarEquipOnPunch;
public static ConfigEntry<bool> UnsheatheAfterSwimming;
public static ConfigEntry<bool> UnsheatheOnPunch;
private readonly Harmony Harmony = new Harmony("com.riintouge.nounarmedcombat");
private void Awake()
{
IsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "Enable", true, "Whether this plugin has any effect when loaded.");
LoadOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "LoadOnStart", true, "Whether this plugin loads on game start.");
AllowKick = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "AllowKick", false, "Allow the player to kick.");
FallbackFisticuffs = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "FallbackFisticuffs", true, "Allow the player to punch and kick when they have no weapon to equip.");
ToolbarEquipOnPunch = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ToolbarEquipOnPunch", true, "Instead of punching and if nothing is sheathed, equip gear from the toolbar, left to right.");
UnsheatheAfterSwimming = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "UnsheatheAfterSwimming", false, "Unsheathe equipment when exiting water that was put away upon swimming.");
UnsheatheOnPunch = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "UnsheatheOnPunch", true, "Instead of punching, equip sheathed equipment. Takes precedence over equipment on the toolbar.");
if (LoadOnStart.Value)
{
Harmony.PatchAll();
}
}
}