using System;
using System.Collections.Generic;
using System.Diagnostics;
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 BetterUI.Patches;
using Casualheim.attack_cancel;
using Casualheim.gui;
using Casualheim.leveling;
using Casualheim.patches;
using HarmonyLib;
using MonoMod.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Casualheim")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Casualheim")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("260c10ac-6c86-41da-be4b-e5891db32a21")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Casualheim
{
[BepInPlugin("Casualheim", "Casualheim", "1.1.2")]
[BepInProcess("valheim.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class ThisPlugin : BaseUnityPlugin
{
public static Harmony harmony_instance = null;
public const string PluginName = "Casualheim";
public const string PluginAuthor = "k-Knight";
public const string PluginVersion = "1.1.2";
public const string PluginGUID = "Casualheim";
public static ConfigEntry<bool> PluginEnabled;
public static ConfigEntry<bool> DebugOutput;
public static ConfigEntry<int> NumberOfPlayersMax;
public static ConfigEntry<bool> AllowClearedBuilding;
public static ConfigEntry<float> ChopMineDamageMultiplier;
public static ConfigEntry<bool> EasierSkillCurveEnabled;
public static ConfigEntry<float> RequiredExpMultiplier;
public static ConfigEntry<bool> EnableDeathPenaltyMod;
public static ConfigEntry<float> DeathPenaltyMultiplier;
public static ConfigEntry<bool> EnableSkillLevelProgressLoss;
public static ConfigEntry<float> EnemyLevelChanceMultiplier;
public static ConfigEntry<bool> EnableAttackMod;
public static ConfigEntry<int> PercentAttackMovement;
public static ConfigEntry<int> PercentAttackRotation;
public static ConfigEntry<bool> PreventDodgeSpamming;
public static ConfigEntry<bool> EnableEnemyHealthMod;
public static ConfigEntry<int> PercentCharredTwitcher;
public static ConfigEntry<int> PercentCharredArcher;
public static ConfigEntry<int> PercentCharredMelee;
public static ConfigEntry<int> PercentCharredMage;
public static ConfigEntry<int> PercentCharredTwitcherSummoned;
public static ConfigEntry<int> PercentFallenValkyrie;
public static ConfigEntry<int> PercentBonemawSerpent;
public static ConfigEntry<int> PercentMorgen;
public static ConfigEntry<int> PercentVolture;
public static ConfigEntry<int> PercentPieceCharredBalista;
public static ConfigEntry<int> PercentBlobLava;
public static ConfigEntry<int> PercentDvergerAshlands;
public static ConfigEntry<bool> EnableBossHealthRegenMod;
public static ConfigEntry<int> RegenerationMultiplier;
public static ConfigEntry<int> PercentRegenEikthyr;
public static ConfigEntry<int> PercentRegenElder;
public static ConfigEntry<int> PercentRegenBonemass;
public static ConfigEntry<int> PercentRegenModer;
public static ConfigEntry<int> PercentRegenYagluth;
public static ConfigEntry<int> PercentRegenQueen;
public static ConfigEntry<int> PercentRegenFader;
public static ConfigEntry<int> PercentHealthEikthyr;
public static ConfigEntry<int> PercentHealthElder;
public static ConfigEntry<int> PercentHealthBonemass;
public static ConfigEntry<int> PercentHealthModer;
public static ConfigEntry<int> PercentHealthYagluth;
public static ConfigEntry<int> PercentHealthQueen;
public static ConfigEntry<int> PercentHealthFader;
public static ConfigEntry<bool> EnableLeveling;
public static ConfigEntry<float> HealthBoostMultiplier;
public static ConfigEntry<float> HealthRegenBoostMultiplier;
public static ConfigEntry<float> StaminaBoostMultiplier;
public static ConfigEntry<float> StaminaRegenBoostMultiplier;
public static ConfigEntry<float> SpeedBoostMultiplier;
public static ConfigEntry<float> JumpHeightMultiplier;
public static ConfigEntry<float> FallWindowMultiplier;
public static Dictionary<string, WeakReference<ConfigEntry<int>>> MaxHealthPercentDict = new Dictionary<string, WeakReference<ConfigEntry<int>>>();
public static Dictionary<string, WeakReference<ConfigEntry<int>>> HealthRegenPercentDict = new Dictionary<string, WeakReference<ConfigEntry<int>>>();
private static ThisPlugin thisInstance;
public static ThisPlugin instance => thisInstance;
public static bool ModIsLoaded(string GUID)
{
foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
{
if (pluginInfo.Value.Metadata.GUID.Equals(GUID))
{
return true;
}
}
return false;
}
public void Awake()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
thisInstance = this;
MaxHealthDictsInit();
LoadSettings();
if (!PluginEnabled.Value)
{
return;
}
harmony_instance = new Harmony("Casualheim");
harmony_instance.PatchAll(typeof(AllowClearedBuildingPatch));
harmony_instance.PatchAll(typeof(AttackSlowdownPatch));
harmony_instance.PatchAll(typeof(DeathPenaltyPatch));
harmony_instance.PatchAll(typeof(EnemyLevelChancePatch));
harmony_instance.PatchAll(typeof(MaxHealthPatch));
harmony_instance.PatchAll(typeof(RegenPatch));
harmony_instance.PatchAll(typeof(SkillCurvePatch));
harmony_instance.PatchAll(typeof(MiningChoppingPatch));
harmony_instance.PatchAll(typeof(AttackCancelPatch));
harmony_instance.PatchAll(typeof(AttackPreventLogicPatch));
harmony_instance.PatchAll(typeof(LevelPatch));
harmony_instance.PatchAll(typeof(StatModificationPatch));
if (ModIsLoaded("MK_BetterUI"))
{
if (DebugOutput.Value)
{
Debug.Log((object)"Casualheim | found optional BetterUI dependency, patching ...");
}
harmony_instance.PatchAll(typeof(DisableBetterUIXPPatch));
}
harmony_instance.PatchAll(typeof(LevelIndicatorPatch));
}
public void OnDestroy()
{
if (harmony_instance != null)
{
harmony_instance.UnpatchSelf();
}
}
public static void MaxHealthDictsInit()
{
MaxHealthPercentDict.Add("charred_twitcher", new WeakReference<ConfigEntry<int>>(PercentCharredTwitcher));
MaxHealthPercentDict.Add("charred_archer", new WeakReference<ConfigEntry<int>>(PercentCharredArcher));
MaxHealthPercentDict.Add("charred_melee", new WeakReference<ConfigEntry<int>>(PercentCharredMelee));
MaxHealthPercentDict.Add("charred_mage", new WeakReference<ConfigEntry<int>>(PercentCharredMage));
MaxHealthPercentDict.Add("charred_twitcher_summoned", new WeakReference<ConfigEntry<int>>(PercentCharredTwitcherSummoned));
MaxHealthPercentDict.Add("fallenvalkyrie", new WeakReference<ConfigEntry<int>>(PercentFallenValkyrie));
MaxHealthPercentDict.Add("bonemawserpent", new WeakReference<ConfigEntry<int>>(PercentBonemawSerpent));
MaxHealthPercentDict.Add("morgen", new WeakReference<ConfigEntry<int>>(PercentMorgen));
MaxHealthPercentDict.Add("volture", new WeakReference<ConfigEntry<int>>(PercentVolture));
MaxHealthPercentDict.Add("piece_charred_balista", new WeakReference<ConfigEntry<int>>(PercentPieceCharredBalista));
MaxHealthPercentDict.Add("bloblava", new WeakReference<ConfigEntry<int>>(PercentBlobLava));
MaxHealthPercentDict.Add("dvergerashlands", new WeakReference<ConfigEntry<int>>(PercentDvergerAshlands));
MaxHealthPercentDict.Add("eikthyr", new WeakReference<ConfigEntry<int>>(PercentHealthEikthyr));
MaxHealthPercentDict.Add("gdking", new WeakReference<ConfigEntry<int>>(PercentHealthElder));
MaxHealthPercentDict.Add("bonemass", new WeakReference<ConfigEntry<int>>(PercentHealthBonemass));
MaxHealthPercentDict.Add("dragon", new WeakReference<ConfigEntry<int>>(PercentHealthModer));
MaxHealthPercentDict.Add("goblinking", new WeakReference<ConfigEntry<int>>(PercentHealthYagluth));
MaxHealthPercentDict.Add("seekerqueen", new WeakReference<ConfigEntry<int>>(PercentHealthQueen));
MaxHealthPercentDict.Add("fader", new WeakReference<ConfigEntry<int>>(PercentHealthFader));
HealthRegenPercentDict.Add("eikthyr", new WeakReference<ConfigEntry<int>>(PercentRegenEikthyr));
HealthRegenPercentDict.Add("gdking", new WeakReference<ConfigEntry<int>>(PercentRegenElder));
HealthRegenPercentDict.Add("bonemass", new WeakReference<ConfigEntry<int>>(PercentRegenBonemass));
HealthRegenPercentDict.Add("dragon", new WeakReference<ConfigEntry<int>>(PercentRegenModer));
HealthRegenPercentDict.Add("goblinking", new WeakReference<ConfigEntry<int>>(PercentRegenYagluth));
HealthRegenPercentDict.Add("seekerqueen", new WeakReference<ConfigEntry<int>>(PercentRegenQueen));
HealthRegenPercentDict.Add("fader", new WeakReference<ConfigEntry<int>>(PercentRegenFader));
}
public static void LoadSettings()
{
PluginEnabled = ((BaseUnityPlugin)instance).Config.Bind<bool>("General", "Enabled", true, "Enable/disable this pulgin.");
DebugOutput = ((BaseUnityPlugin)instance).Config.Bind<bool>("General", "Debug", false, "Enable/disable debug logging.");
NumberOfPlayersMax = ((BaseUnityPlugin)instance).Config.Bind<int>("General", "Number of players max", 4, "Maximum number of active players to modify boss health and regen.");
EnemyLevelChanceMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("General", "Enemy level chance multiplier", 3f, "My how much the chance of leveling up enemy (stars) is multiplied (1.0 for default values).");
AllowClearedBuilding = ((BaseUnityPlugin)instance).Config.Bind<bool>("General", "Allow cleared dungeon building", true, "Allow building in dungeons/locations when all enemies are dead. May require a new world (kinda).");
ChopMineDamageMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("General", "Multiplier for chop/mine damage", 2f, "Multiplies the damage of chopping and mining (0 for disable).");
EasierSkillCurveEnabled = ((BaseUnityPlugin)instance).Config.Bind<bool>("Skills", "Enable easier skill curve", true, "Enables/Disables easier skill curve.");
RequiredExpMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Skills", "Required exp multiplier", 1f, "This changes the speed of arithmetic progression in required experience to reach next skill level.");
EnableDeathPenaltyMod = ((BaseUnityPlugin)instance).Config.Bind<bool>("Skills", "Enable death penalty changes", true, "Enables/Disables modifications of death penalty.");
DeathPenaltyMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Skills", "Death penalty multiplier", 0f, "This changes the amount of skill loss by multiplying it with this value.");
EnableSkillLevelProgressLoss = ((BaseUnityPlugin)instance).Config.Bind<bool>("Skills", "Enable skill level progress loss", false, "Whether to reset the accumulated experience on the current skill level.");
EnableAttackMod = ((BaseUnityPlugin)instance).Config.Bind<bool>("Attacks", "Enable attack changes", true, "Enables/Disables attack cancellation and other related things.");
PercentAttackMovement = ((BaseUnityPlugin)instance).Config.Bind<int>("Attacks", "Percent attack movement speed", 20, "Percent of normal movement speed that remains while attacking (20% is game's default).");
PercentAttackRotation = ((BaseUnityPlugin)instance).Config.Bind<int>("Attacks", "Percent attack rotation speed", 20, "Percent of normal rotation speed that remains while attacking (20% is game's default).");
PreventDodgeSpamming = ((BaseUnityPlugin)instance).Config.Bind<bool>("Attacks", "Prevent dodge spamming", false, "Prevent dodge spamming if player continiously holds down the dodge key.");
EnableEnemyHealthMod = ((BaseUnityPlugin)instance).Config.Bind<bool>("Mob Health", "Enable enemy health change", true, "Enables/Disables the change of enemies' max health.");
PercentCharredTwitcher = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent Charred Twitcher health", 100, "Percent of normal health that Charred Twitcher will have.");
PercentCharredArcher = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent CharredArcher health", 100, "Percent of normal health that Charred Marksman will have.");
PercentCharredMelee = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent CharredMelee health", 66, "Percent of normal health that Charred Warrior will have.");
PercentCharredMage = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent CharredMage health", 66, "Percent of normal health that Charred Warlock will have.");
PercentCharredTwitcherSummoned = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent CharredTwitcherSummoned health", 100, "Percent of normal health that Summoned Twitcher will have.");
PercentFallenValkyrie = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent FallenValkyrie health", 50, "Percent of normal health that Fallen Valkyrie will have.");
PercentBonemawSerpent = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent BonemawSerpent health", 50, "Percent of normal health that Bonemaw Serpent will have.");
PercentMorgen = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent Morgen health", 50, "Percent of normal health that Morgen will have.");
PercentVolture = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent Volture health", 100, "Percent of normal health that Volture will have.");
PercentPieceCharredBalista = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent PieceCharredBalista health", 100, "Percent of normal health that Skugg will have.");
PercentBlobLava = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent BlobLava health", 100, "Percent of normal health that Lava Blob will have.");
PercentDvergerAshlands = ((BaseUnityPlugin)instance).Config.Bind<int>("Mob Health", "Percent DvergerAshlands health", 100, "Percent of normal health that Ashlands Dvergr will have.");
EnableBossHealthRegenMod = ((BaseUnityPlugin)instance).Config.Bind<bool>("Boss Health", "Enable boss health change", true, "Enables/Disables the change of boss max health and regen.");
PercentRegenEikthyr = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Eikthyr", 0, "Percent of normal Eikthyr health regen.");
PercentRegenElder = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Elder", 0, "Percent of normal Elder health regen.");
PercentRegenBonemass = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Bonemass", 0, "Percent of normal Bonemass health regen.");
PercentRegenModer = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Moder", 0, "Percent of normal Moder health regen.");
PercentRegenYagluth = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Yagluth", 0, "Percent of normal Yagluth health regen.");
PercentRegenQueen = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Queen", 0, "Percent of normal Queen health regen.");
PercentRegenFader = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent regen Fader", 0, "Percent of normal Fader health regen.");
PercentHealthEikthyr = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Eikthyr", 150, "Percent of normal Eikthyr max health.");
PercentHealthElder = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Elder", 100, "Percent of normal Elder max health.");
PercentHealthBonemass = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Bonemass", 100, "Percent of normal Bonemass max health.");
PercentHealthModer = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Moder", 100, "Percent of normal Moder max health.");
PercentHealthYagluth = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Yagluth", 100, "Percent of normal Yagluth max health.");
PercentHealthQueen = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Queen", 100, "Percent of normal Queen max health.");
PercentHealthFader = ((BaseUnityPlugin)instance).Config.Bind<int>("Boss Health", "Percent health Fader", 60, "Percent of normal Fader max health.");
EnableLeveling = ((BaseUnityPlugin)instance).Config.Bind<bool>("Leveling", "Enable leveling system", true, "Enables/Disables the leveling system");
HealthBoostMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Health boost strength multiplier", 1f, "Changes the strength of the health boost (0 for disable).");
HealthRegenBoostMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Health regen boost strength multiplier", 1f, "Changes the strength of the health regeneration boost (0 for disable).");
StaminaBoostMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Stamina boost strength multiplier", 1f, "Changes the strength of the stamina boost (0 for disable).");
StaminaRegenBoostMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Stamina regen boost strength multiplier", 1f, "Changes the strength of the stamina regeneration boost (0 for disable).");
SpeedBoostMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Speed boost strength multiplier", 1f, "Changes the strength of the movement speed boost (0 for disable).");
JumpHeightMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Jump height boost strength multiplier", 1f, "Changes the strength of the jump height boost (0 for disable).");
FallWindowMultiplier = ((BaseUnityPlugin)instance).Config.Bind<float>("Leveling", "Allowed fall window increase multiplier", 1f, "Changes the strength of allowed fall window increase where player does not receive fall damage (0 for disable).");
}
}
public static class Util
{
public static HashSet<string> unique_callers = new HashSet<string>();
public static void print_callstack(string caller_method)
{
StackFrame[] frames = new StackTrace(fNeedFileInfo: true).GetFrames();
string text = "\n";
for (int i = 1; i < frames.Length; i++)
{
text = text + " " + new string(' ', i * 2) + frames[i].GetMethod().ToString() + "\n";
}
if (!unique_callers.Contains(text))
{
unique_callers.Add(text);
Debug.Log((object)"");
Debug.Log((object)("in " + caller_method + "()"));
Debug.Log((object)text);
}
}
public static bool check_caller(string caller_method)
{
StackFrame[] frames = new StackTrace(fNeedFileInfo: true).GetFrames();
for (int i = 2; i < frames.Length; i++)
{
if (frames[i].GetMethod().Name == caller_method)
{
return true;
}
}
return false;
}
public static bool check_caller(Type caller_type, string caller_name_part)
{
StackFrame[] frames = new StackTrace(fNeedFileInfo: true).GetFrames();
for (int i = 2; i < frames.Length; i++)
{
MethodBase method = frames[i].GetMethod();
if (ReflectionHelper.GetRealDeclaringType((MemberInfo)method) == caller_type && method.Name.Contains(caller_name_part))
{
return true;
}
}
return false;
}
public static bool GetLocation<T>(ref T obj, out Location loc) where T : MonoBehaviour
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
loc = Location.GetLocation(((Component)obj).transform.position, true);
if ((Object)(object)loc == (Object)null)
{
return false;
}
return true;
}
public static bool GetSyncThings<T>(ref T obj, out ZNetView nview, out ZDO zdo) where T : MonoBehaviour
{
zdo = null;
nview = null;
if (typeof(CreatureSpawner).IsAssignableFrom(((object)obj).GetType()))
{
object obj2 = obj;
nview = ((CreatureSpawner)((obj2 is CreatureSpawner) ? obj2 : null)).m_nview;
}
else if (typeof(SpawnArea).IsAssignableFrom(((object)obj).GetType()))
{
object obj3 = obj;
nview = ((SpawnArea)((obj3 is SpawnArea) ? obj3 : null)).m_nview;
}
else if (typeof(Character).IsAssignableFrom(((object)obj).GetType()))
{
object obj4 = obj;
nview = ((Character)((obj4 is Character) ? obj4 : null)).m_nview;
}
if ((Object)(object)nview == (Object)null)
{
return false;
}
zdo = nview.GetZDO();
if (zdo == null)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | !!! !!! no ZDO for " + ((object)obj).GetType()?.ToString() + " !!! !!!"));
}
return false;
}
return true;
}
public static bool TryGetPlayerZDO(ref Character character, out Player player, out ZDO zdo)
{
player = null;
zdo = null;
if (((object)character).GetType() != typeof(Player))
{
return false;
}
Character obj = character;
player = (Player)(object)((obj is Player) ? obj : null);
return TryGetPlayerZDO(ref player, out zdo);
}
public static bool TryGetPlayerZDO(ref Player player, out ZDO zdo)
{
zdo = ((Character)player).m_nview.GetZDO();
if (zdo == null)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.StatModificationPatch | zdo of a player is null !!!");
}
return false;
}
return true;
}
}
}
namespace Casualheim.patches
{
[HarmonyPatch]
public class AllowClearedBuildingPatch
{
public static int last_zone_location_hash = -1;
public static int last_creature_spawner_hash = -1;
public static int last_character_drop_hash = -1;
public static Dictionary<int, int> loc_2_zloc_dict = new Dictionary<int, int>();
public static bool AssignLocHashDeterministic<T>(ref T obj, out ZDO zdo, out int zloc_hash) where T : MonoBehaviour
{
zloc_hash = 0;
zdo = null;
if (!Util.check_caller("DMD<ZoneSystem::SpawnLocation>"))
{
return false;
}
if (!Util.GetSyncThings(ref obj, out var nview, out zdo))
{
return false;
}
if (!nview.IsOwner())
{
return false;
}
if (zdo.GetBool("zloc_checked", false))
{
zloc_hash = zdo.GetInt("zloc_hash", 0);
return true;
}
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | DETERMINISICALLY found zloc hash for " + ((object)obj).GetType()?.ToString() + " :: " + zloc_hash));
}
zdo.Set("zloc_checked", true);
zdo.Set("zloc_hash", last_zone_location_hash);
zloc_hash = last_zone_location_hash;
return true;
}
public static bool AssignLocHashHeuristic<T>(ref T obj, ref ZDO zdo, out int zloc_hash) where T : MonoBehaviour
{
zloc_hash = 0;
if (zdo.GetBool("zloc_checked", false))
{
zloc_hash = zdo.GetInt("zloc_hash", 0);
return true;
}
Util.GetLocation(ref obj, out var loc);
if ((Object)(object)loc == (Object)null)
{
return false;
}
if (!loc_2_zloc_dict.ContainsKey(((object)loc).GetHashCode()))
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim | CreatureSpawner.Spawn location is not in the dictrionary !!!");
}
return false;
}
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | HEURISTICALLY found zloc hash for " + ((object)obj).GetType()?.ToString() + " :: " + zloc_hash));
}
zloc_hash = loc_2_zloc_dict[((object)loc).GetHashCode()];
zdo.Set("zloc_checked", true);
zdo.Set("zloc_hash", zloc_hash);
return true;
}
public static void BeforeSpawnerUnitSpawn<T>(ref T obj) where T : MonoBehaviour
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.AllowClearedBuilding.Value)
{
return;
}
last_creature_spawner_hash = 0;
if (Util.GetSyncThings(ref obj, out var nview, out var zdo))
{
last_creature_spawner_hash = zdo.GetInt("zloc_hash", 0);
if (last_creature_spawner_hash == 0 && nview.IsOwner() && AssignLocHashHeuristic(ref obj, ref zdo, out var zloc_hash))
{
last_creature_spawner_hash = zloc_hash;
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Location), "IsInside")]
public static void LocationIsInsidePatch(ref Location __instance, ref bool __result, ref bool buildCheck, ref Vector3 point)
{
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)__instance == (Object)null || !buildCheck || !__instance.m_noBuild || !__result || !ThisPlugin.PluginEnabled.Value || !ThisPlugin.AllowClearedBuilding.Value)
{
return;
}
if (!loc_2_zloc_dict.ContainsKey(((object)__instance).GetHashCode()))
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim | Location.IsInside location is not in the dictrionary !!!");
}
return;
}
bool flag = true;
int num = loc_2_zloc_dict[((object)__instance).GetHashCode()];
if (ZoneSystem.m_instance.GetLocation(num) == null)
{
return;
}
foreach (CreatureSpawner creatureSpawner in CreatureSpawner.m_creatureSpawners)
{
if ((Object)(object)creatureSpawner == (Object)null || (Object)(object)creatureSpawner.m_nview == (Object)null)
{
continue;
}
ZDO zDO = creatureSpawner.m_nview.GetZDO();
if (zDO == null)
{
continue;
}
int @int = zDO.GetInt("zloc_hash", 0);
ZDOID connectionZDOID = zDO.GetConnectionZDOID((ConnectionType)3);
if (num == @int && creatureSpawner.SpawnedCreatureStillExists(connectionZDOID))
{
flag = false;
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | creaturespawner [" + ((object)creatureSpawner).GetHashCode() + "] says char still exists for zloc [" + num + "] !"));
}
break;
}
}
if (!flag)
{
return;
}
foreach (Character s_character in Character.s_characters)
{
if ((Object)(object)s_character == (Object)null || (Object)(object)s_character.m_nview == (Object)null)
{
continue;
}
ZDO zDO2 = s_character.m_nview.GetZDO();
if (zDO2 == null)
{
continue;
}
int int2 = zDO2.GetInt("zloc_hash", 0);
if (num == int2)
{
flag = false;
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | found char " + s_character.m_name.ToLower() + " that is still alive for zloc [" + num + "] !"));
}
break;
}
}
if (flag)
{
__instance.m_noBuild = false;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Location), "Awake")]
public static void LocatioAwakenPatch(ref Location __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.AllowClearedBuilding.Value && Util.check_caller("DMD<ZoneSystem::SpawnLocation>"))
{
loc_2_zloc_dict.Add(((object)__instance).GetHashCode(), last_zone_location_hash);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(CharacterDrop), "OnDeath")]
public static void CharacterDropOnDeathPatch(ref CharacterDrop __instance)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.AllowClearedBuilding.Value)
{
return;
}
last_character_drop_hash = 0;
if (!((Object)(object)__instance.m_character == (Object)null) && !((Object)(object)__instance.m_character.m_nview == (Object)null))
{
ZDO zDO = __instance.m_character.m_nview.GetZDO();
if (zDO != null)
{
last_character_drop_hash = zDO.GetInt("zloc_hash", 0);
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ZoneSystem), "SpawnLocation")]
public static void ZoneSystemSpawnLocationPatch(ref ZoneLocation location)
{
last_zone_location_hash = 0;
last_zone_location_hash = location.Hash;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Character), "Awake")]
public static void CharacterAwakePatch(ref Character __instance)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.AllowClearedBuilding.Value)
{
return;
}
bool flag = false;
bool flag2 = false;
if (Util.check_caller("DMD<CreatureSpawner::Spawn>"))
{
flag = true;
}
else if (Util.check_caller("DMD<CharacterDrop::OnDeath>"))
{
flag2 = true;
}
if ((!flag && !flag2) || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsOwner())
{
return;
}
ZDO zDO = __instance.m_nview.GetZDO();
if (zDO != null)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | setting zloc_hash [" + (flag ? last_creature_spawner_hash : (flag2 ? last_character_drop_hash : (-1))) + "] for char :: " + __instance.m_name.ToLower()));
}
if (flag)
{
zDO.Set("zloc_hash", last_creature_spawner_hash);
}
else if (flag2)
{
zDO.Set("zloc_hash", last_character_drop_hash);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(CreatureSpawner), "Awake")]
public static void CreatureSpawnerAwakePatch(ref CreatureSpawner __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.AllowClearedBuilding.Value)
{
AllowClearedBuildingPatch.AssignLocHashDeterministic<CreatureSpawner>(ref __instance, out ZDO _, out int _);
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SpawnArea), "Awake")]
public static void SpawnAreaAwakePatch(ref SpawnArea __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.AllowClearedBuilding.Value)
{
AllowClearedBuildingPatch.AssignLocHashDeterministic<SpawnArea>(ref __instance, out ZDO _, out int _);
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(CreatureSpawner), "Spawn")]
public static void CreatureSpawnerSpawnPatch(ref CreatureSpawner __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.AllowClearedBuilding.Value)
{
AllowClearedBuildingPatch.BeforeSpawnerUnitSpawn<CreatureSpawner>(ref __instance);
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SpawnArea), "SpawnOne")]
public static void SpawnAreaSpawnOnePatch(ref SpawnArea __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.AllowClearedBuilding.Value)
{
AllowClearedBuildingPatch.BeforeSpawnerUnitSpawn<SpawnArea>(ref __instance);
}
}
}
[HarmonyPatch(typeof(Skills), "LowerAllSkills")]
public class DeathPenaltyPatch
{
public static bool Prefix(ref Skills __instance, ref float factor)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableDeathPenaltyMod.Value)
{
return true;
}
factor *= ThisPlugin.DeathPenaltyMultiplier.Value;
foreach (KeyValuePair<SkillType, Skill> skillDatum in __instance.m_skillData)
{
if ((double)factor >= 0.01)
{
float num = skillDatum.Value.m_level * factor;
Skill value = skillDatum.Value;
value.m_level -= num;
}
if (ThisPlugin.EnableSkillLevelProgressLoss.Value)
{
skillDatum.Value.m_accumulator = 0f;
}
}
((Character)__instance.m_player).Message((MessageType)1, "$msg_skills_lowered", 0, (Sprite)null);
return false;
}
}
[HarmonyPatch]
public class EnemyLevelChancePatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(SpawnArea), "GetLevelUpChance")]
public static void SpawnAreaLevelUpChancePatch(ref SpawnArea __instance, ref float __result)
{
if (ThisPlugin.PluginEnabled.Value)
{
__result *= ThisPlugin.EnemyLevelChanceMultiplier.Value;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(SpawnSystem), "GetLevelUpChance", new Type[] { typeof(float) })]
public static void SpawnSystemLevelUpChancePatch(ref float __result)
{
if (ThisPlugin.PluginEnabled.Value)
{
__result *= ThisPlugin.EnemyLevelChanceMultiplier.Value;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(TriggerSpawner), "Awake")]
public static void TriggerSpawnerLevelUpChancePatch(ref TriggerSpawner __instance)
{
if (ThisPlugin.PluginEnabled.Value)
{
TriggerSpawner obj = __instance;
obj.m_levelupChance *= ThisPlugin.EnemyLevelChanceMultiplier.Value;
}
}
}
[HarmonyPatch(typeof(Character), "SetMaxHealth")]
public class MaxHealthPatch
{
public static void Prefix(Character __instance, ref float health)
{
if (!ThisPlugin.PluginEnabled.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (__instance.IsBoss() && (Player.GetAllPlayers().Count > ThisPlugin.NumberOfPlayersMax.Value || !ThisPlugin.EnableBossHealthRegenMod.Value)) || (!__instance.IsBoss() && !ThisPlugin.EnableEnemyHealthMod.Value))
{
return;
}
string text = __instance.m_name.ToLower();
if (text.StartsWith("$enemy_"))
{
text = text.Substring("$enemy_".Length);
}
ConfigEntry<int> target;
if (!ThisPlugin.MaxHealthPercentDict.TryGetValue(text, out var value))
{
if (ThisPlugin.DebugOutput.Value && text != "human")
{
Debug.Log((object)("Casualheim | !!! unmatched enemy normal max health " + text + " :: " + health));
}
}
else if (value.TryGetTarget(out target))
{
health *= (float)target.Value / 100f;
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim.MaxHealthPatch :: " + text + " :: " + health));
}
}
}
}
[HarmonyPatch]
public class MiningChoppingPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(DamageTypes), "GetTotalDamage")]
public static bool DamageTypesGetTotalDamagePatch(ref DamageTypes __instance, ref float __result)
{
float value = ThisPlugin.ChopMineDamageMultiplier.Value;
if ((double)value < 0.001)
{
return true;
}
__result = __instance.m_damage + __instance.m_blunt + __instance.m_slash + __instance.m_pierce + __instance.m_chop * value + __instance.m_pickaxe * value + __instance.m_fire + __instance.m_frost + __instance.m_lightning + __instance.m_poison + __instance.m_spirit;
return false;
}
}
[HarmonyPatch(typeof(Skill), "GetNextLevelRequirement")]
public class SkillCurvePatch
{
public static bool Prefix(Skill __instance, ref float __result)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EasierSkillCurveEnabled.Value)
{
return true;
}
__result = Mathf.Floor(__instance.m_level + 1f) * ThisPlugin.RequiredExpMultiplier.Value;
return false;
}
}
[HarmonyPatch(typeof(Character), "Heal")]
public class RegenPatch
{
public static void Prefix(Character __instance, ref float hp)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableBossHealthRegenMod.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (__instance.IsBoss() && Player.GetAllPlayers().Count > ThisPlugin.NumberOfPlayersMax.Value))
{
return;
}
string text = __instance.m_name.ToLower();
if (text.StartsWith("$enemy_"))
{
text = text.Substring("$enemy_".Length);
}
if (ThisPlugin.HealthRegenPercentDict.TryGetValue(text, out var value) && value.TryGetTarget(out var target))
{
hp *= (float)target.Value / 100f;
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim.RegenPatch :: " + text + " :: " + __instance.GetHealth() + " / " + __instance.GetMaxHealth() + "(+" + hp + ")"));
}
}
}
}
[HarmonyPatch]
public class AttackSlowdownPatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(Humanoid), "GetAttackSpeedFactorMovement")]
public static void AttackMovementSpeedPatch(Humanoid __instance, ref float __result)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableAttackMod.Value && __result < 0.99f && ((object)__instance).GetType() == typeof(Player) && ThisPlugin.PluginEnabled.Value)
{
__result = (float)ThisPlugin.PercentAttackMovement.Value / 100f;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Humanoid), "GetAttackSpeedFactorRotation")]
public static void AttackRotationSpeedPatch(Humanoid __instance, ref float __result)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableAttackMod.Value && __result < 0.99f && ((object)__instance).GetType() == typeof(Player) && ThisPlugin.PluginEnabled.Value)
{
__result = (float)ThisPlugin.PercentAttackRotation.Value / 100f;
}
}
}
}
namespace Casualheim.leveling
{
[HarmonyPatch]
public class DisableBetterUIXPPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(XP), "Awake")]
public static bool DisableXPAwake()
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(XP), "RaiseXP")]
public static bool DisableXPRaiseXP()
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(XP), "UpdateLevelProgressPercentage")]
public static bool DisableXPUpdateLevelProgressPercentage()
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(XP), "GetNextLevelRequirement")]
public static bool DisableXPGetNextLevelRequirement(ref float __result)
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
__result = 1f;
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(XPBar), "Create")]
public static bool DisableXPBarCreate()
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(XPBar), "UpdateLevelProgressPercentage")]
public static bool DisableXPBarUpdateLevelProgressPercentage()
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(XPBar), "UpdatePosition")]
public static bool DisableXPBarUpdatePosition()
{
if (!ThisPlugin.EnableLeveling.Value)
{
return true;
}
return false;
}
}
public static class Level
{
public static Player player;
public static float total_exp;
public static int level = -1;
public static float next_level_progress;
public static float curr_level_required_xp = 0f;
public static float next_level_required_xp = 1f;
public static void Initialize(ref Player player)
{
Level.player = player;
level = -1;
Update();
}
public static void Update()
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)player == (Object)null))
{
int num = level;
UpdateTotalExp();
UpdateLevel();
UpdateLevelProgress();
LevelIndicatorPatch.Update(level, next_level_progress);
if (num != -1 && num < level)
{
player.m_skillLevelupEffects.Create(((Character)player).m_head.position, ((Character)player).m_head.rotation, ((Character)player).m_head, 1.5f, -1);
((Character)player).Message((MessageType)2, $"<size=60><color=#ffffffff>New Level</color></size>\n<size=30>Reached level {level} </size>", 0, (Sprite)null);
}
}
}
public static void UpdateTotalExp()
{
if ((Object)(object)player == (Object)null)
{
return;
}
float num = 0f;
int num2 = 0;
foreach (Skill value in player.m_skills.m_skillData.Values)
{
num2++;
num += value.m_level;
}
total_exp = num / ((float)num2 * 100f) * 5050f;
}
public static void UpdateLevel()
{
if ((Object)(object)player == (Object)null)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.Level | local player is null !!!");
}
return;
}
level = (int)Math.Floor(Math.Round((-1.0 + Math.Sqrt(8.0 * (double)total_exp + 1.0)) / 2.0, 1));
curr_level_required_xp = GetNextLevelRequirement(level - 1);
next_level_required_xp = GetNextLevelRequirement(level);
if (!ThisPlugin.PluginEnabled.Value)
{
return;
}
if (!((Character)player).m_nview.IsOwner())
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.Level | we are not the owner of the local player !!!");
}
return;
}
ZDO zDO = ((Character)player).m_nview.GetZDO();
if (zDO == null)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.Level | zdo of local player is null !!!");
}
return;
}
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim.Level | current level for local player is :: " + level));
}
zDO.Set("betterui_level", level);
}
public static void UpdateLevelProgress()
{
next_level_progress = (total_exp - curr_level_required_xp) / (next_level_required_xp - curr_level_required_xp);
}
public static float GetNextLevelRequirement(int lvl)
{
return ((float)lvl + 1f) * (2f + (float)lvl) / 2f;
}
}
[HarmonyPatch]
public class LevelPatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(Skills), "LowerAllSkills")]
public static void SkillstLowerAllSkillsPatch()
{
if (ThisPlugin.EnableLeveling.Value)
{
Level.Update();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Skills), "CheatRaiseSkill")]
public static void SkillsCheatRaiseSkillPatch()
{
if (ThisPlugin.EnableLeveling.Value)
{
Level.Update();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Skill), "Raise")]
public static void SkillRaisePatch()
{
if (ThisPlugin.EnableLeveling.Value)
{
Level.Update();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Hud), "Update")]
public static void HudUpdatePatch()
{
if (ThisPlugin.EnableLeveling.Value)
{
Player player = Player.m_localPlayer;
if ((Object)(object)player != (Object)null && ((Object)(object)Level.player == (Object)null || ((object)Level.player).GetHashCode() != ((object)player).GetHashCode()))
{
Level.Initialize(ref player);
}
}
}
}
[HarmonyPatch]
public class StatModificationPatch
{
public static Dictionary<int, float> stamina_values = new Dictionary<int, float>();
public static float GetLevelEffectStrength(ref ZDO zdo, float strength_at_100)
{
return (float)zdo.GetInt("betterui_level", 0) / 100f / (1f / (strength_at_100 - 1f)) + 1f;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Character), "SetMaxHealth")]
public static void CharacterSetMaxHealthPatch(ref Character __instance, ref float health)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.HealthBoostMultiplier.Value != 0f && Util.TryGetPlayerZDO(ref __instance, out var _, out var zdo))
{
float num = GetLevelEffectStrength(ref zdo, 1.5f) * ThisPlugin.HealthBoostMultiplier.Value;
health *= num;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Character), "Heal")]
public static void CharacterHealPatch(Character __instance, ref float hp)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.HealthRegenBoostMultiplier.Value != 0f && Util.TryGetPlayerZDO(ref __instance, out var _, out var zdo))
{
float num = GetLevelEffectStrength(ref zdo, 1.5f) * ThisPlugin.HealthRegenBoostMultiplier.Value;
hp *= num;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "SetMaxStamina")]
public static void PlayerSetMaxStaminaPatch(Player __instance, ref float stamina)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.StaminaBoostMultiplier.Value != 0f && Util.TryGetPlayerZDO(ref __instance, out var zdo))
{
float num = GetLevelEffectStrength(ref zdo, 1.25f) * ThisPlugin.StaminaBoostMultiplier.Value;
stamina *= num;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
public static void PlayerUpdateStatsPatch_Prefix(Player __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.StaminaRegenBoostMultiplier.Value != 0f)
{
stamina_values[((object)__instance).GetHashCode()] = __instance.m_stamina;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
public static void PlayerUpdateStatsPatch_Postfix(Player __instance)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableLeveling.Value || ThisPlugin.StaminaRegenBoostMultiplier.Value == 0f)
{
return;
}
int hashCode = ((object)__instance).GetHashCode();
ZDO zdo;
if (!stamina_values.ContainsKey(hashCode))
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim.StatModificationPatch | stamina_values has no record for player " + ((Character)__instance).m_name + " !!!"));
}
}
else if (Util.TryGetPlayerZDO(ref __instance, out zdo))
{
float num = GetLevelEffectStrength(ref zdo, 2f) * ThisPlugin.StaminaRegenBoostMultiplier.Value;
float num2 = __instance.m_stamina - stamina_values[hashCode];
if (!(num2 <= 0f))
{
__instance.m_stamina = Mathf.Min(((Character)__instance).GetMaxStamina(), num2 * (num - 1f) + __instance.m_stamina);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Player), "GetJogSpeedFactor")]
public static void PlayerGetJogSpeedFactorPatch(Player __instance, ref float __result)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.SpeedBoostMultiplier.Value != 0f && Util.TryGetPlayerZDO(ref __instance, out var zdo))
{
float num = GetLevelEffectStrength(ref zdo, 1.25f) * ThisPlugin.SpeedBoostMultiplier.Value;
__result *= num;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Player), "GetRunSpeedFactor")]
public static void PlayerGetRunSpeedFactorPatch(Player __instance, ref float __result)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.SpeedBoostMultiplier.Value != 0f && Util.TryGetPlayerZDO(ref __instance, out var zdo))
{
float num = GetLevelEffectStrength(ref zdo, 1.25f) * ThisPlugin.SpeedBoostMultiplier.Value;
__result *= num;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Character), "UpdateWalking")]
public static void CharacterUpdateWalkingPatch(Character __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableLeveling.Value && ThisPlugin.SpeedBoostMultiplier.Value != 0f && Util.TryGetPlayerZDO(ref __instance, out var player, out var zdo))
{
float num = GetLevelEffectStrength(ref zdo, 1.25f) * ThisPlugin.SpeedBoostMultiplier.Value;
float num2 = player.m_skills.GetSkillFactor((SkillType)101) * 0.5f + 1f;
float num3 = 1f + ((Character)player).GetEquipmentMovementModifier();
((Character)player).m_crouchSpeed = 2f * num * num2 * num3;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Character), "UpdateGroundContact")]
public static void CharacteUpdateGroundContactPatch_Prefix(Character __instance)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
if (!ThisPlugin.PluginEnabled.Value || !__instance.m_groundContact || !Util.TryGetPlayerZDO(ref __instance, out var player, out var zdo))
{
return;
}
float num = ((Character)player).m_maxAirAltitude - ((Component)player).transform.position.y;
if (!(num <= 0f))
{
float num2 = player.m_skills.GetSkillFactor((SkillType)100) * 0.3f;
Player obj = player;
((Character)obj).m_maxAirAltitude = ((Character)obj).m_maxAirAltitude - num * num2;
if (ThisPlugin.FallWindowMultiplier.Value != 0f)
{
float num3 = (GetLevelEffectStrength(ref zdo, 3f) - 1f) * ThisPlugin.FallWindowMultiplier.Value;
((Character)player).m_maxAirAltitude = Math.Max(((Character)player).m_maxAirAltitude - num3, ((Component)player).transform.position.y);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Skills), "GetSkillFactor")]
public static void SkillsGetSkillFactorPatch(ref Skills __instance, ref float __result, ref SkillType skillType)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.JumpHeightMultiplier.Value != 0f && !((Object)(object)__instance.m_player == (Object)null) && (int)skillType == 100 && Util.TryGetPlayerZDO(ref __instance.m_player, out var zdo) && Util.check_caller(typeof(Character), "Jump"))
{
float num = GetLevelEffectStrength(ref zdo, 1.4f) * ThisPlugin.JumpHeightMultiplier.Value;
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim.StatModificationPatch | icreasing jump force " + num + " times"));
}
__result *= num;
}
}
}
}
namespace Casualheim.gui
{
[HarmonyPatch]
public class LevelIndicatorPatch
{
public const float max_bar_length = 97f;
public static TextMeshProUGUI level_indicator_text;
public static RectTransform level_indicator_bar;
[HarmonyPostfix]
[HarmonyPatch(typeof(InventoryGui), "Awake")]
public static void InventoryGuiAwakePatch()
{
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: 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_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0355: Unknown result type (might be due to invalid IL or missing references)
//IL_0363: Unknown result type (might be due to invalid IL or missing references)
//IL_036f: Unknown result type (might be due to invalid IL or missing references)
//IL_037f: Unknown result type (might be due to invalid IL or missing references)
//IL_0395: Unknown result type (might be due to invalid IL or missing references)
//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0413: Unknown result type (might be due to invalid IL or missing references)
//IL_047f: Unknown result type (might be due to invalid IL or missing references)
//IL_0484: Unknown result type (might be due to invalid IL or missing references)
//IL_0487: Unknown result type (might be due to invalid IL or missing references)
//IL_048c: Unknown result type (might be due to invalid IL or missing references)
//IL_048f: Unknown result type (might be due to invalid IL or missing references)
//IL_0494: Unknown result type (might be due to invalid IL or missing references)
//IL_0497: Unknown result type (might be due to invalid IL or missing references)
//IL_049c: Unknown result type (might be due to invalid IL or missing references)
//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableLeveling.Value)
{
return;
}
level_indicator_text = null;
level_indicator_bar = null;
Transform obj = InventoryGui.m_instance.m_inventoryRoot.Find("Info");
Transform obj2 = ((obj is RectTransform) ? obj : null);
Transform obj3 = obj2.Find("TitlePanel");
RectTransform val = (RectTransform)(object)((obj3 is RectTransform) ? obj3 : null);
Transform obj4 = obj2.Find("Texts");
RectTransform val2 = (RectTransform)(object)((obj4 is RectTransform) ? obj4 : null);
Transform obj5 = obj2.Find("Skills");
RectTransform val3 = (RectTransform)(object)((obj5 is RectTransform) ? obj5 : null);
Transform obj6 = obj2.Find("Trophies");
RectTransform val4 = (RectTransform)(object)((obj6 is RectTransform) ? obj6 : null);
Transform obj7 = obj2.Find("PVP");
Transform obj8 = ((obj7 is RectTransform) ? obj7 : null);
Transform obj9 = ((Transform)val).Find("charactername");
RectTransform val5 = (RectTransform)(object)((obj9 is RectTransform) ? obj9 : null);
Transform obj10 = ((Transform)val).Find("BraidLineHorisontalMedium (1)");
RectTransform val6 = (RectTransform)(object)((obj10 is RectTransform) ? obj10 : null);
Transform obj11 = ((Transform)val).Find("BraidLineHorisontalMedium (2)");
Transform obj12 = ((obj11 is RectTransform) ? obj11 : null);
val6.anchoredPosition = new Vector2(val6.anchoredPosition.x, -13f);
((RectTransform)obj12).anchoredPosition = new Vector2(((RectTransform)obj12).anchoredPosition.x, -13f);
val2.anchoredPosition = new Vector2(val2.anchoredPosition.x, -24f);
val3.anchoredPosition = new Vector2(val3.anchoredPosition.x, -24f);
val4.anchoredPosition = new Vector2(val4.anchoredPosition.x, -24f);
((RectTransform)obj8).anchoredPosition = new Vector2(((RectTransform)obj8).anchoredPosition.x, -24f);
GameObject val7 = null;
GameObject val8 = null;
GuiBar[] array = Resources.FindObjectsOfTypeAll(typeof(GuiBar)) as GuiBar[];
foreach (GuiBar val9 in array)
{
if (((Object)val9).name.Equals("levelbar"))
{
val7 = ((Component)val9).gameObject;
break;
}
}
ButtonSfx[] array2 = Resources.FindObjectsOfTypeAll(typeof(ButtonSfx)) as ButtonSfx[];
foreach (ButtonSfx val10 in array2)
{
if (((Object)val10).name.Equals("Craft"))
{
val8 = ((Component)val10).gameObject;
break;
}
}
Transform obj13 = ((Transform)val).Find("cslh_lvl_indicator");
RectTransform val11 = (RectTransform)(object)((obj13 is RectTransform) ? obj13 : null);
if ((Object)(object)val11 != (Object)null)
{
Object.Destroy((Object)(object)((Component)val11).gameObject);
}
GameObject val12 = Object.Instantiate<GameObject>(val8, (Transform)(object)val);
Component component = val12.GetComponent(typeof(RectTransform));
val11 = (RectTransform)(object)((component is RectTransform) ? component : null);
Object.Destroy((Object)(object)((Component)((Transform)val11).Find("Text")).gameObject);
Object.Destroy((Object)(object)((Component)((Transform)val11).Find("Selected")).gameObject);
Object.Destroy((Object)(object)((Component)((Transform)val11).Find("gamepad_hint")).gameObject);
Object.Destroy((Object)(object)val12.GetComponent(typeof(ButtonSfx)));
Object.Destroy((Object)(object)val12.GetComponent(typeof(UIGamePad)));
Object.Destroy((Object)(object)val12.GetComponent(typeof(ButtonTextColor)));
GameObject obj14 = Object.Instantiate<GameObject>(val7, ((Component)val11).transform);
Component component2 = obj14.GetComponent(typeof(RectTransform));
RectTransform val13 = (RectTransform)(object)((component2 is RectTransform) ? component2 : null);
Debug.Log((object)val13);
Object.Destroy((Object)(object)((Component)((Transform)val13).Find("bkg")).gameObject);
Object.Destroy((Object)(object)((Component)((Transform)val13).Find("bonustext")).gameObject);
Object.Destroy((Object)(object)obj14.GetComponent(typeof(GuiBar)));
((Transform)val11).localPosition = new Vector3(0f, 0f, 0f);
val11.anchoredPosition = new Vector2(val11.anchoredPosition.x, val11.anchoredPosition.y - 26f);
val11.sizeDelta = new Vector2(100f, 22f);
((Object)val12).name = "cslh_lvl_indicator";
val13.anchoredPosition = new Vector2(0f, 0f);
val13.sizeDelta = new Vector2(98.5f, 20f);
((Object)obj14).name = "cslh_lvl_bar_container";
Transform obj15 = ((Transform)val13).Find("bar");
Transform obj16 = ((obj15 is RectTransform) ? obj15 : null);
val13.anchoredPosition = new Vector2(0f, 0f);
((RectTransform)obj16).sizeDelta = new Vector2(97f, 0f);
((Object)((Component)obj16).gameObject).name = "cslh_lvl_bar";
Transform obj17 = ((Transform)val13).Find("leveltext");
Transform obj18 = ((obj17 is RectTransform) ? obj17 : null);
GameObject val14 = Object.Instantiate<GameObject>(((Component)val5).gameObject, (Transform)(object)val13);
Component component3 = val14.GetComponent(typeof(TextMeshProUGUI));
TextMeshProUGUI val15 = (TextMeshProUGUI)(object)((component3 is TextMeshProUGUI) ? component3 : null);
Component component4 = val14.GetComponent(typeof(RectTransform));
RectTransform val16 = (RectTransform)(object)((component4 is RectTransform) ? component4 : null);
Vector2 anchoredPosition = ((RectTransform)obj18).anchoredPosition;
Vector2 offsetMax = ((RectTransform)obj18).offsetMax;
Vector2 offsetMin = ((RectTransform)obj18).offsetMin;
Vector2 sizeDelta = ((RectTransform)obj18).sizeDelta;
val16.anchoredPosition = anchoredPosition;
val16.offsetMax = offsetMax;
val16.offsetMin = offsetMin;
val16.sizeDelta = sizeDelta;
Object.Destroy((Object)(object)((Component)obj18).gameObject);
((Object)val14).name = "cslh_lvl_text";
((Graphic)val15).color = new Color(1f, 0.8667f, 0.6784f, 1f);
((TMP_Text)val15).fontSizeMax = 20f;
level_indicator_text = val15;
level_indicator_bar = (RectTransform)(object)obj16;
}
public static void Update(int level, float progress)
{
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)level_indicator_text == (Object)null) && !((Object)(object)level_indicator_bar == (Object)null))
{
if (progress < 0f)
{
progress = 0f;
}
if (progress > 1f)
{
progress = 1f;
}
((TMP_Text)level_indicator_text).text = "Level " + level;
level_indicator_bar.sizeDelta = new Vector2(97f * progress, level_indicator_bar.sizeDelta.y);
}
}
}
}
namespace Casualheim.attack_cancel
{
public struct BlockInputState
{
public float block_start_time;
public float attack_start_time;
public float dodge_end_time;
public bool block_state;
public bool attack_state;
public bool dodge_state;
}
public struct AttackCancel
{
public float time;
public int atk;
public bool done;
}
public struct DamageDone
{
public int atk;
public float time;
}
public static class State
{
public static Dictionary<int, AttackCancel> last_attack_cancel_dict = new Dictionary<int, AttackCancel>();
public static Dictionary<int, BlockInputState> block_state_dict = new Dictionary<int, BlockInputState>();
public static Dictionary<int, DamageDone> player_attack_damage_done_dict = new Dictionary<int, DamageDone>();
public static Dictionary<int, int> player_in_attack_frame_cached = new Dictionary<int, int>();
public static Dictionary<int, bool> player_started_secondary = new Dictionary<int, bool>();
public static Dictionary<int, WeakReference<Player>> zanim_player_dict = new Dictionary<int, WeakReference<Player>>();
}
[HarmonyPatch]
public class AttackPreventLogicPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(Attack), "Update")]
[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
[HarmonyPatch(typeof(Attack), "ConsumeItem")]
[HarmonyPatch(typeof(Attack), "UseAmmo")]
[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
[HarmonyPatch(typeof(Attack), "DoNonAttack")]
[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
[HarmonyPatch(typeof(Attack), "AddHitPoint")]
[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
[HarmonyPatch(typeof(Attack), "SpawnOnHit")]
[HarmonyPatch(typeof(Attack), "TryAttach")]
[HarmonyPatch(typeof(Attack), "UpdateAttach")]
public static bool PreventLogic(ref Attack __instance)
{
if (__instance.m_abortAttack && ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableAttackMod.Value)
{
return false;
}
return true;
}
}
[HarmonyPatch]
public class AttackCancelPatch
{
public static bool ApplyAnimSpeedup(ref Player p)
{
ItemData currentWeapon = ((Humanoid)p).GetCurrentWeapon();
if (currentWeapon != null && currentWeapon.m_shared != null && currentWeapon.m_shared.m_name != null)
{
string name = currentWeapon.m_shared.m_name;
if (name.Contains("spear"))
{
return false;
}
if (name.Contains("pickaxe"))
{
return false;
}
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Player), "Awake")]
public static void PlayerAwakePatch(ref Player __instance)
{
if ((Object)(object)((Character)__instance).m_zanim == (Object)null)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.PlayerAwakePatch | player m_zanim is null !!!");
}
}
else
{
int hashCode = ((object)__instance).GetHashCode();
State.player_in_attack_frame_cached[hashCode] = MonoUpdaters.UpdateCount;
State.player_started_secondary[hashCode] = false;
State.zanim_player_dict.Add(((object)((Character)__instance).m_zanim).GetHashCode(), new WeakReference<Player>(__instance));
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ZSyncAnimation), "RPC_SetTrigger")]
public static bool ZSyncAnimationRPC_SetTriggerPatch(ref ZSyncAnimation __instance, ref string name)
{
if (!name.StartsWith("csca!"))
{
return true;
}
int hashCode = ((object)__instance).GetHashCode();
if (!State.zanim_player_dict.ContainsKey(hashCode))
{
return true;
}
if (!State.zanim_player_dict[hashCode].TryGetTarget(out var target))
{
return true;
}
Animator animator = ((Character)target).m_animator;
((Character)target).m_animEvent.m_pauseTimer = -1f;
if (ApplyAnimSpeedup(ref target))
{
animator.speed = 1000f;
}
else
{
animator.speed = 1f;
}
animator.ForceStateNormalizedTime(0.99f);
return false;
}
public static void SkipCurrentAttackAnimation(ref Player p)
{
if (((Character)p).GetNextAnimHash() != Humanoid.s_animatorTagAttack && ((Character)p).GetCurrentAnimHash() != Humanoid.s_animatorTagAttack)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.SkipCurrentAttackAnimation | no animation is an attack animation !!!");
}
}
else
{
((Character)p).m_nview.InvokeRPC(ZNetView.Everybody, "SetTrigger", new object[1] { "csca!" });
}
}
public static bool CancelAttack(ref Player p, float attack_min_time)
{
if (((Humanoid)p).m_currentAttack == null)
{
return false;
}
Attack currentAttack = ((Humanoid)p).m_currentAttack;
int hashCode = ((object)p).GetHashCode();
int hashCode2 = ((object)currentAttack).GetHashCode();
float time = currentAttack.m_time;
bool num = State.last_attack_cancel_dict.ContainsKey(hashCode);
bool flag = num && State.last_attack_cancel_dict[hashCode].atk == hashCode2;
bool done = false;
if (num && flag)
{
done = State.last_attack_cancel_dict[hashCode].done;
return true;
}
if (time <= attack_min_time)
{
return false;
}
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.CancelAttack | cancelling");
}
currentAttack.Abort();
SkipCurrentAttackAnimation(ref p);
currentAttack.m_zanim.SetTrigger("attack_abort");
currentAttack.m_zanim.SetTrigger("detach");
((Humanoid)p).m_previousAttack = null;
State.last_attack_cancel_dict[hashCode] = new AttackCancel
{
time = Time.fixedTime,
atk = hashCode2,
done = done
};
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Humanoid), "OnAttackTrigger")]
public static void HumanoidOnAttackTriggerPatch(Humanoid __instance)
{
if (ThisPlugin.PluginEnabled.Value && ThisPlugin.EnableAttackMod.Value && !(((object)__instance).GetType() != typeof(Player)) && __instance.m_currentAttack != null)
{
Humanoid obj = ((__instance is Player) ? __instance : null);
Attack currentAttack = obj.m_currentAttack;
int hashCode = ((object)obj).GetHashCode();
int hashCode2 = ((object)currentAttack).GetHashCode();
if (!State.player_attack_damage_done_dict.ContainsKey(hashCode))
{
State.player_attack_damage_done_dict.Add(hashCode, new DamageDone
{
atk = hashCode2,
time = Time.fixedTime
});
}
else
{
State.player_attack_damage_done_dict[hashCode] = new DamageDone
{
atk = hashCode2,
time = Time.fixedTime
};
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "Dodge")]
public static bool PlayerDodgePatch(Player __instance, ref Vector3 dodgeDir)
{
//IL_002f: 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)
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.PreventDodgeSpamming.Value)
{
return true;
}
if (!((Character)__instance).InDodge())
{
__instance.m_queuedDodgeTimer = 0.5f;
}
__instance.m_queuedDodgeDir = dodgeDir;
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "UpdateDodge")]
public static bool PlayerUpdateDodgePatch(Player __instance, ref float dt)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableAttackMod.Value)
{
return true;
}
if (((Character)__instance).InDodge())
{
return true;
}
int hashCode = ((object)__instance).GetHashCode();
if (!State.block_state_dict.ContainsKey(hashCode) || Time.fixedTime - State.block_state_dict[hashCode].block_start_time > 0.1f)
{
return true;
}
__instance.m_queuedDodgeTimer -= dt;
return false;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Player), "InAttack")]
public static void PlayerInAttackCancelPatch(Player __instance, ref bool __result)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableAttackMod.Value)
{
return;
}
int hashCode = ((object)__instance).GetHashCode();
float fixedTime = Time.fixedTime;
if (State.player_in_attack_frame_cached[hashCode] == MonoUpdaters.UpdateCount)
{
return;
}
bool flag = false;
bool flag2 = false;
if (State.player_attack_damage_done_dict.TryGetValue(hashCode, out var value) && ((Humanoid)__instance).m_currentAttack != null)
{
flag2 = value.atk == ((object)((Humanoid)__instance).m_currentAttack).GetHashCode();
flag = fixedTime - value.time > 1.5f;
}
if (State.last_attack_cancel_dict.ContainsKey(hashCode) && !State.last_attack_cancel_dict[hashCode].done)
{
float num = fixedTime - State.last_attack_cancel_dict[hashCode].time;
if (num < 0.1f)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim | (in attack) attack canceled recently :: " + num + "s --- " + MonoUpdaters.UpdateCount));
}
SkipCurrentAttackAnimation(ref __instance);
__result = false;
__instance.m_cachedAttack = __result;
State.player_in_attack_frame_cached[hashCode] = MonoUpdaters.UpdateCount;
return;
}
AttackCancel value2 = State.last_attack_cancel_dict[hashCode];
value2.done = true;
State.last_attack_cancel_dict[hashCode] = value2;
}
if (((Humanoid)__instance).m_currentAttack == null)
{
return;
}
bool flag3 = ((Humanoid)__instance).m_currentAttack == null || ((Humanoid)__instance).m_currentAttack.IsDone();
StackFrame[] frames = new StackTrace(fNeedFileInfo: true).GetFrames();
bool flag4 = false;
bool flag5 = false;
float attack_min_time = 0f;
for (int i = 1; i < frames.Length; i++)
{
MethodBase method = frames[i].GetMethod();
if (method == null)
{
continue;
}
Type realDeclaringType = ReflectionHelper.GetRealDeclaringType((MemberInfo)method);
string name = method.Name;
if (realDeclaringType == null || name == null)
{
continue;
}
if (realDeclaringType == typeof(Character) && name.Contains("Jump"))
{
flag4 = true;
attack_min_time = 0f;
break;
}
if (realDeclaringType == typeof(Humanoid) && name.Contains("UpdateBlock"))
{
bool flag6 = false;
if (!State.block_state_dict.ContainsKey(hashCode))
{
flag6 = true;
}
if (!flag6)
{
BlockInputState blockInputState = State.block_state_dict[hashCode];
if (blockInputState.attack_start_time < blockInputState.block_start_time)
{
flag6 = true;
}
}
if (flag6)
{
flag4 = true;
flag5 = true;
attack_min_time = 0.1f;
}
break;
}
if (realDeclaringType == typeof(Player) && name.Contains("UpdateDodge"))
{
float num2 = __instance.m_dodgeStaminaUsage - __instance.m_dodgeStaminaUsage * ((Character)__instance).GetEquipmentMovementModifier() + __instance.m_dodgeStaminaUsage * ((Character)__instance).GetEquipmentDodgeStaminaModifier();
((Character)__instance).m_seman.ModifyDodgeStaminaUsage(num2, ref num2, true);
if (((Character)__instance).HaveStamina(num2))
{
flag4 = true;
attack_min_time = 0.1f;
}
break;
}
}
if ((!flag2 || flag || flag5) && flag4 && (!flag3 || flag))
{
((Humanoid)__instance).ClearActionQueue();
__result = !CancelAttack(ref __instance, attack_min_time);
__instance.m_cachedAttack = __result;
if (!__result && flag5)
{
((Character)__instance).m_nview.GetZDO().Set(ZDOVars.s_isBlockingHash, true);
((Character)__instance).m_zanim.SetBool(Humanoid.s_blocking, true);
}
State.player_in_attack_frame_cached[hashCode] = MonoUpdaters.UpdateCount;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Humanoid), "StartAttack")]
public static bool HumanoidStartAttackCancelPatch_Prefix(Humanoid __instance, ref bool __result)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableAttackMod.Value)
{
return true;
}
if (((object)__instance).GetType() != typeof(Player))
{
return true;
}
int hashCode = ((object)((__instance is Player) ? __instance : null)).GetHashCode();
float fixedTime = Time.fixedTime;
if (State.last_attack_cancel_dict.ContainsKey(hashCode))
{
float num = fixedTime - State.last_attack_cancel_dict[hashCode].time;
if (num < 0.5f)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)("Casualheim.HumanoidStartAttackCancelPatch | attack canceled recently :: " + num + "s"));
}
__result = false;
return false;
}
}
else if (State.block_state_dict.ContainsKey(hashCode))
{
BlockInputState blockInputState = State.block_state_dict[hashCode];
if ((blockInputState.block_state && blockInputState.block_start_time > blockInputState.attack_start_time) || blockInputState.dodge_state || fixedTime - blockInputState.dodge_end_time < 0.15f || !blockInputState.attack_state)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.HumanoidStartAttackCancelPatch | block/dodge");
}
__result = false;
return false;
}
}
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.HumanoidStartAttackCancelPatch | starting attack ...");
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Humanoid), "StartAttack")]
public static void HumanoidStartAttackCancelPatch_Postfix(Humanoid __instance, ref bool __result, ref bool secondaryAttack)
{
if (__result && ((Character)__instance).IsPlayer())
{
State.player_started_secondary[((object)((__instance is Player) ? __instance : null)).GetHashCode()] = secondaryAttack;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "SetControls")]
public static void PlayerSetControlsPatch(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool dodge)
{
if (!ThisPlugin.PluginEnabled.Value || !ThisPlugin.EnableAttackMod.Value)
{
return;
}
int hashCode = ((object)__instance).GetHashCode();
bool flag = block | blockHold;
bool flag2 = (attack | attackHold | secondaryAttack | secondaryAttackHold) || ((Humanoid)__instance).m_attackDrawTime > 0.01f;
bool inDodge = __instance.m_inDodge;
float fixedTime = Time.fixedTime;
float num;
float num2;
float num3;
if (!State.block_state_dict.ContainsKey(hashCode))
{
num = (flag ? fixedTime : (-2f));
num2 = (inDodge ? fixedTime : (-2f));
num3 = (flag2 ? fixedTime : (-1f));
State.block_state_dict.Add(hashCode, new BlockInputState
{
block_state = flag,
block_start_time = num,
attack_state = flag2,
attack_start_time = num3,
dodge_state = inDodge,
dodge_end_time = num2
});
}
else
{
BlockInputState blockInputState = State.block_state_dict[hashCode];
num = ((!blockInputState.block_state && flag) ? fixedTime : blockInputState.block_start_time);
num3 = ((!blockInputState.attack_state && flag2) ? fixedTime : blockInputState.attack_start_time);
num2 = ((!inDodge) ? blockInputState.dodge_end_time : fixedTime);
State.block_state_dict[hashCode] = new BlockInputState
{
block_state = flag,
block_start_time = num,
attack_state = flag2,
attack_start_time = num3,
dodge_state = inDodge,
dodge_end_time = num2
};
}
if ((flag && num > num3) || inDodge || fixedTime - num2 < 0.15f)
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.PlayerSetControlsPatch | stopping attack input due to block/dodge");
}
attack = false;
attackHold = false;
secondaryAttack = false;
secondaryAttackHold = false;
}
else if (State.last_attack_cancel_dict.ContainsKey(hashCode) && !(Time.fixedTime - State.last_attack_cancel_dict[hashCode].time >= 0.1f))
{
if (ThisPlugin.DebugOutput.Value)
{
Debug.Log((object)"Casualheim.PlayerSetControlsPatch | stopping attack input due recent cancelled attack");
}
attack = false;
attackHold = false;
secondaryAttack = false;
secondaryAttackHold = false;
}
}
}
}