Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RaiderClans v1.0.0
RaiderClans.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RaiderClans")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Hostile Player-Model Raiders & Infused Loot Mod for Valheim")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RaiderClans")] [assembly: AssemblyTitle("RaiderClans")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RaiderClans { public interface IRaiderBehaviorFactory { void Attach(GameObject raiderObject); } public interface IStructureAttackAugment { bool CanApply(HitData hitData, Piece targetPiece); void Apply(HitData hitData, Piece targetPiece); } public sealed class TorchFireAugment : IStructureAttackAugment { public bool CanApply(HitData hitData, Piece targetPiece) { return false; } public void Apply(HitData hitData, Piece targetPiece) { RaiderClansPlugin.LogDebug("[TorchFireAugment] Would ignite " + (((targetPiece != null) ? ((Object)targetPiece).name : null) ?? "<null>") + " once fire system is ready."); } } public sealed class PillagerBehaviorFactory : IRaiderBehaviorFactory { private static readonly StructurePriority[] DefaultPriorities = new StructurePriority[17] { new StructurePriority("guard_stone", null, 0), new StructurePriority("portal_wood", null, 1), new StructurePriority("piece_workbench", null, 2), new StructurePriority("piece_stonecutter", null, 3), new StructurePriority("forge", null, 4), new StructurePriority("blackforge", null, 5), new StructurePriority("mage_table", null, 6), new StructurePriority("artisan_table", null, 7), new StructurePriority(null, (PieceCategory)1, 8), new StructurePriority("piece_chest_blackmetal", null, 9), new StructurePriority("piece_chest_private", null, 10), new StructurePriority("piece_chest_wood", null, 11), new StructurePriority("piece_door_iron", null, 12), new StructurePriority("piece_door_secret", null, 13), new StructurePriority("piece_door", null, 14), new StructurePriority(null, (PieceCategory)3, 15), new StructurePriority(null, (PieceCategory)2, 16) }; private readonly IReadOnlyList<StructurePriority> _priorities; private readonly float _searchRadius; private readonly float _scanInterval; private readonly List<IStructureAttackAugment> _augments; private PillagerBehaviorFactory(IReadOnlyList<StructurePriority> priorities, float searchRadius, float scanInterval, IEnumerable<IStructureAttackAugment> augments) { _priorities = priorities; _searchRadius = searchRadius; _scanInterval = scanInterval; _augments = new List<IStructureAttackAugment>(augments ?? Array.Empty<IStructureAttackAugment>()); } public static PillagerBehaviorFactory CreateDefault() { return new PillagerBehaviorFactory(DefaultPriorities, 45f, 5f, new TorchFireAugment[1] { new TorchFireAugment() }); } public void Attach(GameObject raiderObject) { if (!((Object)(object)raiderObject == (Object)null)) { PillagerBehavior pillagerBehavior = raiderObject.GetComponent<PillagerBehavior>(); if ((Object)(object)pillagerBehavior == (Object)null) { pillagerBehavior = raiderObject.AddComponent<PillagerBehavior>(); } pillagerBehavior.Configure(_priorities, _searchRadius, _scanInterval, _augments); MonsterAI component = raiderObject.GetComponent<MonsterAI>(); if ((Object)(object)component != (Object)null) { component.m_enableHuntPlayer = false; ((BaseAI)component).SetHuntPlayer(false); } } } } public class PillagerBehavior : MonoBehaviour { private enum PillagerState { Searching, StructureCommitted, AggroPlayer, NoStructures } private const float AggroMemorySeconds = 10f; private const float BlockCheckInterval = 0.5f; private const float BlockingDetectionRadius = 2.5f; private const float StructureProgressSampleInterval = 2f; private const float StructureProgressThreshold = 1.5f; private const float StructureStuckTimeout = 6f; private static readonly FieldRef<MonsterAI, StaticTarget> TargetStaticField = AccessTools.FieldRefAccess<MonsterAI, StaticTarget>("m_targetStatic"); private static readonly FieldRef<MonsterAI, Character> TargetCreatureField = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature"); private MonsterAI _monsterAI; private BaseAI _baseAI; private Character _character; private ZNetView _nview; private readonly List<Piece> _structureBuffer = new List<Piece>(64); private readonly List<IStructureAttackAugment> _augments = new List<IStructureAttackAugment>(); private IReadOnlyList<StructurePriority> _priorities = Array.Empty<StructurePriority>(); private float _searchRadius = 40f; private float _scanInterval = 5f; private float _nextScanTime; private float _nextBlockCheck; private Piece _currentStructureTarget; private Character _currentAggressor; private float _aggroExpiry; private float _structureProgressSampleTime; private float _previousStructureDistance; private float _structureStuckTimer; private PillagerState _state = PillagerState.Searching; public void Configure(IReadOnlyList<StructurePriority> priorities, float searchRadius, float scanInterval, IEnumerable<IStructureAttackAugment> augments) { _priorities = priorities ?? Array.Empty<StructurePriority>(); _searchRadius = Mathf.Max(5f, searchRadius); _scanInterval = Mathf.Max(1f, scanInterval); _augments.Clear(); if (augments != null) { _augments.AddRange(augments); } } private void Awake() { _monsterAI = ((Component)this).GetComponent<MonsterAI>(); _baseAI = (BaseAI)(object)_monsterAI; _character = ((Component)this).GetComponent<Character>(); _nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_character != (Object)null) { Character character = _character; character.m_onDamaged = (Action<float, Character>)Delegate.Combine(character.m_onDamaged, new Action<float, Character>(OnDamaged)); } } private void OnDestroy() { if ((Object)(object)_character != (Object)null) { Character character = _character; character.m_onDamaged = (Action<float, Character>)Delegate.Remove(character.m_onDamaged, new Action<float, Character>(OnDamaged)); } } private void Update() { if (!ShouldRun()) { return; } float deltaTime = Time.deltaTime; if (UpdateAggroState()) { MaintainAggressorTarget(); return; } MaintainStructureTarget(deltaTime); ScanForStructureTargets(); if ((Object)(object)_currentStructureTarget != (Object)null) { CheckBlockingPlayer(); } } internal static void TryHandleStructureHit(Character attacker, Piece targetPiece, HitData hitData) { if (!((Object)(object)attacker == (Object)null) && !((Object)(object)targetPiece == (Object)null) && hitData != null) { ((Component)attacker).GetComponent<PillagerBehavior>()?.ApplyAugments(targetPiece, hitData); } } private bool ShouldRun() { if ((Object)(object)_monsterAI == (Object)null || (Object)(object)_baseAI == (Object)null || (Object)(object)_character == (Object)null || (Object)(object)_nview == (Object)null) { return false; } if (!_nview.IsValid() || !_nview.IsOwner()) { return false; } return true; } private void OnDamaged(float damage, Character attacker) { if (!((Object)(object)attacker == (Object)null) && !attacker.IsDead() && attacker.IsPlayer()) { AdoptAggressor(attacker); } } private bool UpdateAggroState() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentAggressor == (Object)null) { return false; } _state = PillagerState.AggroPlayer; if (_currentAggressor.IsDead() || Time.time > _aggroExpiry || Vector3.Distance(((Component)_currentAggressor).transform.position, ((Component)this).transform.position) > _searchRadius * 1.5f) { ClearAggressor(); } return (Object)(object)_currentAggressor != (Object)null; } private void MaintainAggressorTarget() { if (!((Object)(object)_monsterAI == (Object)null) && !((Object)(object)_currentAggressor == (Object)null)) { TargetStaticField.Invoke(_monsterAI) = null; Character val = TargetCreatureField.Invoke(_monsterAI); if ((Object)(object)val != (Object)(object)_currentAggressor) { TargetCreatureField.Invoke(_monsterAI) = _currentAggressor; } ((BaseAI)_monsterAI).Alert(); } } private void ClearAggressor() { _currentAggressor = null; _aggroExpiry = 0f; if ((Object)(object)_monsterAI != (Object)null) { TargetCreatureField.Invoke(_monsterAI) = null; if (((BaseAI)_monsterAI).HuntPlayer()) { ((BaseAI)_monsterAI).SetHuntPlayer(false); } } _state = (((Object)(object)_currentStructureTarget != (Object)null) ? PillagerState.StructureCommitted : PillagerState.Searching); } private void AdoptAggressor(Character aggressor) { if (!((Object)(object)aggressor == (Object)null)) { _currentAggressor = aggressor; _aggroExpiry = Time.time + 10f; BaseAI baseAI = _baseAI; if (baseAI != null) { baseAI.SetAggravated(true, (AggravatedReason)0); } if ((Object)(object)_monsterAI != (Object)null && !((BaseAI)_monsterAI).HuntPlayer()) { ((BaseAI)_monsterAI).SetHuntPlayer(true); } } } private void ScanForStructureTargets() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextScanTime) { return; } _nextScanTime = Time.time + _scanInterval; if (!HasValidStructureTarget()) { RaiderTargetingService.FindPlayerStructures(((Component)this).transform.position, _searchRadius, _structureBuffer); Piece val = RaiderTargetingService.SelectHighestPriorityStructure(_structureBuffer, _priorities, ((Component)this).transform.position); if ((Object)(object)val == (Object)null) { HandleNoStructuresFound(); } else { AssignStructureTarget(val); } } } private void MaintainStructureTarget(float dt) { if (HasValidStructureTarget()) { StaticTarget val = TargetStaticField.Invoke(_monsterAI); if ((Object)(object)val != (Object)(object)_currentStructureTarget) { TargetStaticField.Invoke(_monsterAI) = (StaticTarget)(object)_currentStructureTarget; TargetCreatureField.Invoke(_monsterAI) = null; } UpdateStructureProgress(dt); } } internal bool ShouldPreferStructureTarget() { return (Object)(object)_currentStructureTarget != (Object)null && (Object)(object)_currentAggressor == (Object)null; } private void AssignStructureTarget(Piece piece) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) _currentStructureTarget = piece; if (!((Object)(object)_monsterAI == (Object)null)) { TargetCreatureField.Invoke(_monsterAI) = null; TargetStaticField.Invoke(_monsterAI) = (StaticTarget)(object)piece; BaseAI baseAI = _baseAI; if (baseAI != null) { baseAI.SetAggravated(true, (AggravatedReason)0); } ((BaseAI)_monsterAI).Alert(); _state = PillagerState.StructureCommitted; _structureStuckTimer = 0f; _previousStructureDistance = Vector3.Distance(((Component)this).transform.position, ((Component)piece).transform.position); _structureProgressSampleTime = Time.time + 2f; } } private void ClearStructureTarget() { _currentStructureTarget = null; if ((Object)(object)_monsterAI != (Object)null) { TargetStaticField.Invoke(_monsterAI) = null; } _state = PillagerState.Searching; _structureStuckTimer = 0f; } private void CheckBlockingPlayer() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentStructureTarget == (Object)null || Time.time < _nextBlockCheck) { return; } _nextBlockCheck = Time.time + 0.5f; Character val = RaiderTargetingService.FindBlockingPlayer(((Component)this).transform.position, ((Component)_currentStructureTarget).transform.position, 2.5f); if ((Object)(object)val != (Object)null && val.IsPlayer()) { MonsterAI monsterAI = _monsterAI; if (monsterAI != null) { ((BaseAI)monsterAI).Alert(); } } } private void ApplyAugments(Piece targetPiece, HitData hitData) { if ((Object)(object)targetPiece == (Object)null || hitData == null || _augments.Count == 0) { return; } foreach (IStructureAttackAugment augment in _augments) { if (augment != null && augment.CanApply(hitData, targetPiece)) { augment.Apply(hitData, targetPiece); } } } private bool HasValidStructureTarget() { if ((Object)(object)_currentStructureTarget == (Object)null) { return false; } if ((Object)(object)((Component)_currentStructureTarget).gameObject == (Object)null || !((Component)_currentStructureTarget).gameObject.activeInHierarchy || !_currentStructureTarget.IsPlacedByPlayer()) { ClearStructureTarget(); return false; } return true; } private void UpdateStructureProgress(float dt) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentStructureTarget == (Object)null) { return; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)_currentStructureTarget).transform.position); if (num <= 2.5f) { _structureStuckTimer = 0f; } else { if (Time.time < _structureProgressSampleTime) { return; } float num2 = _previousStructureDistance - num; if (num2 < 1.5f) { _structureStuckTimer += 2f; if (_structureStuckTimer >= 6f) { RaiderClansPlugin.LogDebug("[PillagerBehavior] Structure target unreachable, searching for a new one."); ClearStructureTarget(); return; } } else { _structureStuckTimer = 0f; } _previousStructureDistance = num; _structureProgressSampleTime = Time.time + 2f; } } private void HandleNoStructuresFound() { _state = PillagerState.NoStructures; TargetStaticField.Invoke(_monsterAI) = null; } } [HarmonyPatch(typeof(WearNTear), "RPC_Damage")] internal static class PillagerStructureHitPatch { private static void Prefix(WearNTear __instance, HitData hit) { if ((Object)(object)__instance == (Object)null || hit == null) { return; } Character attacker = hit.GetAttacker(); if (!((Object)(object)attacker == (Object)null)) { Piece component = ((Component)__instance).GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { PillagerBehavior.TryHandleStructureHit(attacker, component, hit); } } } } public class RaiderAI { public readonly struct RaiderSpawnRequest { public Vector3 Position { get; } public Biome Biome { get; } public RaiderRole Role { get; } public RaiderSpawnRequest(Vector3 position, Biome biome, RaiderRole role) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Position = position; Biome = biome; Role = role; } } public const string RaiderCustomDataKey = "RaiderClans_IsRaider"; private const string ChieftainCustomDataKey = "RaiderClans_IsChieftain"; private const string BiomeCustomDataKey = "RaiderClans_Biome"; private const string RoleCustomDataKey = "RaiderClans_Role"; private const string MinimalPrefabName = "RaiderClan_Minimal"; private static bool s_minimalPrefabRegistered; private static readonly Dictionary<RaiderRole, StatusEffect> s_damageEffects = new Dictionary<RaiderRole, StatusEffect>(); public static void Initialize() { RaiderRoleRegistry.Initialize(); PrefabManager.OnVanillaPrefabsAvailable += RegisterMinimalRaiderPrefab; } private static void RegisterMinimalRaiderPrefab() { if (!s_minimalPrefabRegistered) { RaiderClansPlugin.LogDebug("Registering minimal raider NPC prefab via Jotunn"); GameObject val = CreateMinimalRaiderPrefab("RaiderClan_Minimal"); if ((Object)(object)val != (Object)null) { PrefabManager.Instance.AddPrefab(val); s_minimalPrefabRegistered = true; RaiderClansPlugin.Logger.LogInfo((object)"Minimal raider prefab registered successfully via Jotunn"); } else { RaiderClansPlugin.Logger.LogError((object)"Failed to register minimal raider prefab"); } } } private static GameObject CreateMinimalRaiderPrefab(string prefabName) { //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Expected O, but got Unknown //IL_01f9: Unknown result type (might be due to invalid IL or missing references) RaiderClansPlugin.LogDebug("Creating " + prefabName + " prefab (minimal Player clone)"); GameObject val = PrefabManager.Instance.CreateClonedPrefab(prefabName, "Player"); if ((Object)(object)val == (Object)null) { RaiderClansPlugin.Logger.LogError((object)"Failed to clone Player prefab"); return null; } PlayerController component = val.GetComponent<PlayerController>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } AudioListener[] componentsInChildren = val.GetComponentsInChildren<AudioListener>(true); foreach (AudioListener val2 in componentsInChildren) { Object.DestroyImmediate((Object)(object)val2); } GuidePoint[] componentsInChildren2 = val.GetComponentsInChildren<GuidePoint>(true); foreach (GuidePoint val3 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val3); } Player component2 = val.GetComponent<Player>(); if ((Object)(object)component2 == (Object)null) { RaiderClansPlugin.Logger.LogError((object)"Player clone missing Player component!"); return null; } ItemDrop unarmedWeapon = ((Humanoid)component2).m_unarmedWeapon; EffectList consumeItemEffects = ((Humanoid)component2).m_consumeItemEffects; EffectList equipEffects = ((Humanoid)component2).m_equipEffects; Object.DestroyImmediate((Object)(object)component2); Humanoid val4 = val.AddComponent<Humanoid>(); val4.m_unarmedWeapon = unarmedWeapon; val4.m_consumeItemEffects = consumeItemEffects; val4.m_equipEffects = equipEffects; Character val5 = (Character)(object)val4; if ((Object)(object)val5 != (Object)null) { val5.m_name = "Clan Raider"; val5.m_group = "Raiders"; val5.m_faction = (Faction)3; val5.m_walkSpeed = 2f; val5.m_runSpeed = 4f; val5.m_health = 100f; val5.m_staggerWhenBlocked = true; val5.m_staggerDamageFactor = 0.2f; Transform val6 = Utils.FindChild(val.transform, "EyePos", (IterativeSearchType)0); if ((Object)(object)val6 == (Object)null) { GameObject val7 = new GameObject("EyePos"); val7.transform.SetParent(val.transform); val7.transform.localPosition = new Vector3(0f, 1.6f, 0f); val6 = val7.transform; } val5.m_eye = val6; CharacterDrop val8 = val.GetComponent<CharacterDrop>(); if ((Object)(object)val8 == (Object)null) { val8 = val.AddComponent<CharacterDrop>(); } val8.m_dropsEnabled = true; } MonsterAI val9 = val.AddComponent<MonsterAI>(); ((BaseAI)val9).m_viewRange = 60f; ((BaseAI)val9).m_viewAngle = 90f; ((BaseAI)val9).m_hearRange = 30f; ((BaseAI)val9).m_aggravatable = true; val9.m_attackPlayerObjects = true; val9.m_enableHuntPlayer = true; val9.m_minAttackInterval = 2f; val9.m_circleTargetInterval = 0f; ((BaseAI)val9).m_randomMoveInterval = 1f; ((BaseAI)val9).m_randomMoveRange = 5f; RaiderClansPlugin.LogDebug(prefabName + " prefab created successfully"); return val; } public static Humanoid SpawnRaider(Vector3 position, Biome biome, bool isChieftain = false, bool isRanged = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) RaiderRole role = (isChieftain ? RaiderRole.Chieftain : RaiderRole.Warrior); if (isRanged) { RaiderClansPlugin.LogDebug("Ranged raiders not yet implemented; defaulting to melee role behavior."); } return SpawnRaider(new RaiderSpawnRequest(position, biome, role)); } public static Humanoid SpawnRaider(RaiderSpawnRequest request) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected I4, but got Unknown //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) RaiderClansPlugin.LogDebug($"Attempting to spawn raider role {request.Role} at {request.Position}"); GameObject prefab = ZNetScene.instance.GetPrefab("RaiderClan_Minimal"); if ((Object)(object)prefab == (Object)null) { RaiderClansPlugin.Logger.LogError((object)"Could not find RaiderClan_Minimal template in ZNetScene"); return null; } RaiderRoleConfig config = RaiderRoleRegistry.GetConfig(request.Role); Vector3 position = request.Position; Biome biome = request.Biome; GameObject val = Object.Instantiate<GameObject>(prefab, position, Quaternion.identity); if ((Object)(object)val == (Object)null) { RaiderClansPlugin.Logger.LogError((object)"Failed to instantiate raider"); return null; } RaiderClansPlugin.LogDebug("Spawned minimal raider instance: " + ((Object)val).name); Humanoid component = val.GetComponent<Humanoid>(); if ((Object)(object)component == (Object)null) { RaiderClansPlugin.Logger.LogError((object)"Failed to get Humanoid component from spawned raider"); ZNetScene.instance.Destroy(val); return null; } Character component2 = ((Component)component).GetComponent<Character>(); if ((Object)(object)component2 == (Object)null) { RaiderClansPlugin.Logger.LogError((object)"Spawned raider missing Character component"); ZNetScene.instance.Destroy(val); return null; } component2.m_faction = (Faction)3; component2.m_name = "Clan Raider"; ZNetView val2 = ((Character)component).m_nview ?? val.GetComponent<ZNetView>(); ZDO val3 = ((val2 != null) ? val2.GetZDO() : null); if (val3 != null) { val3.Set("RaiderClans_IsRaider", true); val3.Set("RaiderClans_IsChieftain", request.Role == RaiderRole.Chieftain); val3.Set("RaiderClans_Biome", (int)biome); val3.Set("RaiderClans_Role", (int)request.Role); } else { RaiderClansPlugin.Logger.LogWarning((object)"Spawned raider without valid ZDO; custom metadata unavailable"); } float baseHealthForBiome = RaiderRoleRegistry.GetBaseHealthForBiome(biome); float num = Mathf.Max(50f, baseHealthForBiome * config.HealthMultiplier); component2.SetMaxHealth(num); component2.SetHealth(num); CharacterDrop component3 = val.GetComponent<CharacterDrop>(); RaiderLoot.ConfigureCharacterDrop(component3, biome); ApplyRoleConfiguration(component, val, config, biome); RaiderClansPlugin.LogDebug("Successfully spawned minimal raider"); return component; } private static void ApplyRoleConfiguration(Humanoid raider, GameObject raiderObj, RaiderRoleConfig config, Biome biome) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)raider == (Object)null || config == null) { return; } Character component = ((Component)raider).GetComponent<Character>(); if ((Object)(object)component != (Object)null) { component.m_name = "Clan " + config.DisplayName; component.m_walkSpeed *= config.MoveSpeedMultiplier; component.m_runSpeed *= config.MoveSpeedMultiplier; if (Mathf.Abs(config.ModelScale - 1f) > 0.01f) { raiderObj.transform.localScale = Vector3.Scale(raiderObj.transform.localScale, new Vector3(config.ModelScale, config.ModelScale, config.ModelScale)); } } MonsterAI component2 = ((Component)raider).GetComponent<MonsterAI>(); if ((Object)(object)component2 != (Object)null) { ((BaseAI)component2).m_pathAgentType = (AgentType)10; if (config.Role == RaiderRole.Pillager) { component2.m_enableHuntPlayer = false; ((BaseAI)component2).SetHuntPlayer(false); } } ApplyDefaultItems(raider, config.ResolveDefaultItems(biome)); config.BehaviorFactory?.Attach(raiderObj); ApplyDamageMultiplier(component, config); } private static void ApplyDefaultItems(Humanoid humanoid, IReadOnlyList<string> prefabNames) { if ((Object)(object)humanoid == (Object)null || prefabNames == null || prefabNames.Count == 0) { return; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { RaiderClansPlugin.Logger.LogWarning((object)"ObjectDB not ready; cannot equip raider role items."); return; } List<GameObject> list = new List<GameObject>(); foreach (string prefabName in prefabNames) { if (!string.IsNullOrWhiteSpace(prefabName)) { GameObject itemPrefab = instance.GetItemPrefab(prefabName); if ((Object)(object)itemPrefab != (Object)null) { list.Add(itemPrefab); } else { RaiderClansPlugin.Logger.LogWarning((object)("Missing item prefab '" + prefabName + "' for raider role " + ((Object)humanoid).name)); } } } if (list.Count != 0) { humanoid.m_defaultItems = list.ToArray(); GameObject[] defaultItems = humanoid.m_defaultItems; foreach (GameObject val in defaultItems) { humanoid.GiveDefaultItem(val); } } } private static void ApplyDamageMultiplier(Character character, RaiderRoleConfig config) { if ((Object)(object)character == (Object)null || config == null || Mathf.Approximately(config.DamageMultiplier, 1f)) { return; } SEMan sEMan = character.GetSEMan(); if (sEMan != null) { StatusEffect damageEffectTemplate = GetDamageEffectTemplate(config); if ((Object)(object)damageEffectTemplate != (Object)null) { sEMan.AddStatusEffect(damageEffectTemplate, true, 0, 0f); } } } private static StatusEffect GetDamageEffectTemplate(RaiderRoleConfig config) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown if (s_damageEffects.TryGetValue(config.Role, out var value)) { return value; } SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)val).name = $"SE_Raider_{config.Role}_Damage"; ((StatusEffect)val).m_name = ((Object)val).name; val.m_damageModifier = config.DamageMultiplier; val.m_modifyAttackSkill = (SkillType)999; ((StatusEffect)val).m_icon = null; ((StatusEffect)val).m_tooltip = string.Empty; ((StatusEffect)val).m_startEffects = new EffectList(); ((StatusEffect)val).m_stopEffects = new EffectList(); ((StatusEffect)val).m_ttl = 0f; ((StatusEffect)val).m_cooldown = 0f; s_damageEffects[config.Role] = (StatusEffect)(object)val; return (StatusEffect)(object)val; } public static bool IsRaider(Character character) { if (character?.m_nview?.m_zdo == null) { return false; } return character.m_nview.m_zdo.GetBool("RaiderClans_IsRaider", false); } public static RaiderRole? GetRole(Character character) { if (character?.m_nview?.m_zdo == null) { return null; } int num = character.m_nview.m_zdo.GetInt("RaiderClans_Role", -1); if (num == -1) { return null; } return (RaiderRole)num; } public static bool IsChieftain(Character character) { if (character?.m_nview?.m_zdo == null) { return false; } return character.m_nview.m_zdo.GetBool("RaiderClans_IsChieftain", false); } } [HarmonyPatch] internal class RaiderClansDevCommands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; public static ConsoleOptionsFetcher <>9__0_1; public static ConsoleEvent <>9__0_2; public static ConsoleOptionsFetcher <>9__0_3; public static ConsoleOptionsFetcher <>9__0_4; public static ConsoleEvent <>9__0_5; public static ConsoleEvent <>9__0_6; public static ConsoleEvent <>9__0_7; public static ConsoleEvent <>9__0_8; public static ConsoleOptionsFetcher <>9__0_9; public static ConsoleEvent <>9__0_10; public static ConsoleOptionsFetcher <>9__0_11; public static ConsoleEvent <>9__0_12; public static ConsoleEvent <>9__0_13; internal void <AddCustomCommands>b__0_0(ConsoleEventArgs args) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); return; } Biome val = (Biome)1; if (args.Length >= 2) { if (Enum.TryParse<Biome>(args[1], ignoreCase: true, out Biome result)) { val = result; } else { args.Context.AddString("Invalid biome: " + args[1] + ". Using Meadows."); } } bool result2 = false; if (args.Length >= 3) { bool.TryParse(args[2], out result2); } Vector3 val2 = ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 3f; Humanoid val3 = RaiderAI.SpawnRaider(val2, val, result2); if ((Object)(object)val3 != (Object)null) { args.Context.AddString(string.Format("Spawned {0} for biome {1} at {2}", result2 ? "Chieftain" : "Raider", val, val2)); RaiderClansPlugin.Logger.LogInfo((object)$"Dev command spawned raider: Biome={val}, Chieftain={result2}, Pos={val2}"); } else { args.Context.AddString("Failed to spawn raider - check logs"); } } internal List<string> <AddCustomCommands>b__0_1() { return new List<string> { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands" }; } internal void <AddCustomCommands>b__0_2(ConsoleEventArgs args) { //IL_004e: 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) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else if (args.Length >= 2) { if (Enum.TryParse<Biome>(args[1], ignoreCase: true, out Biome result)) { RaiderEvents.StartRaidManually(result); args.Context.AddString($"Raider clan raid event started for {result}!"); RaiderClansPlugin.Logger.LogInfo((object)$"Dev command started raid event for biome {result}"); } else { args.Context.AddString("Invalid biome '" + args[1] + "'."); } } else { RaiderEvents.StartRaidManually(); args.Context.AddString("Raider clan raid event started!"); RaiderClansPlugin.Logger.LogInfo((object)"Dev command started raid event"); } } internal List<string> <AddCustomCommands>b__0_3() { return new List<string> { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands" }; } internal List<string> <AddCustomCommands>b__0_4() { return new List<string> { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands" }; } internal void <AddCustomCommands>b__0_5(ConsoleEventArgs args) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0046: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); return; } Vector2i zone = ZoneSystem.GetZone(((Component)Player.m_localPlayer).transform.position); args.Context.AddString($"Processing zone {zone}..."); RaiderClansPlugin.Logger.LogInfo((object)$"Dev command processing zone: {zone}"); int num = RaiderTowerOverwrites.ProcessZoneLocations(zone); args.Context.AddString($"Processed {num} locations in zone {zone}"); } internal void <AddCustomCommands>b__0_6(ConsoleEventArgs args) { if (args.Length >= 2) { if (args[1].ToLower() == "on") { RaiderClansPlugin.EnableDebugLogging.Value = true; args.Context.AddString("Debug logging enabled"); } else if (args[1].ToLower() == "off") { RaiderClansPlugin.EnableDebugLogging.Value = false; args.Context.AddString("Debug logging disabled"); } } else { args.Context.AddString("Debug logging is currently " + (RaiderClansPlugin.EnableDebugLogging.Value ? "enabled" : "disabled")); } } internal void <AddCustomCommands>b__0_7(ConsoleEventArgs args) { HashSet<string> processedLocations = RaiderTowerOverwrites.GetProcessedLocations(); args.Context.AddString($"Processed {processedLocations.Count} locations:"); foreach (string item in processedLocations) { args.Context.AddString(" - " + item); } } internal void <AddCustomCommands>b__0_8(ConsoleEventArgs args) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); return; } if (args.Length < 2 || !Enum.TryParse<RaiderRole>(args[1], ignoreCase: true, out var result)) { args.Context.AddString("Usage: raiderclan_spawnrole <Warrior|Pillager|Chieftain> [Biome]"); return; } Biome val = (Biome)1; if (args.Length >= 3 && Enum.TryParse<Biome>(args[2], ignoreCase: true, out Biome result2)) { val = result2; } Vector3 val2 = ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 3f; Humanoid val3 = RaiderAI.SpawnRaider(new RaiderAI.RaiderSpawnRequest(val2, val, result)); args.Context.AddString(((Object)(object)val3 != (Object)null) ? $"Spawned {result} with {val} loadout at {val2}" : "Failed to spawn raider"); } internal List<string> <AddCustomCommands>b__0_9() { return new List<string> { "Warrior", "Pillager", "Chieftain" }; } internal void <AddCustomCommands>b__0_10(ConsoleEventArgs args) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); return; } if (args.Length < 2) { args.Context.AddString("Usage: raiderclan_spawngarrison <tower|village> [radius]"); return; } string text = args[1].ToLowerInvariant(); float num = 20f; if (args.Length >= 3 && float.TryParse(args[2], out var result)) { num = Mathf.Clamp(result, 5f, 50f); } GameObject val = new GameObject("RaiderClans_GarrisonRoot"); val.transform.position = ((Component)Player.m_localPlayer).transform.position; if (text == "tower") { RaiderTowerOverwrites.SpawnTowerRaiders(val); args.Context.AddString($"Spawned tower garrison at {val.transform.position} (radius {num})"); } else if (text == "village") { RaiderTowerOverwrites.SpawnVillageRaiders(val); args.Context.AddString($"Spawned village garrison at {val.transform.position} (radius {num})"); } else { args.Context.AddString("Invalid garrison type. Use 'tower' or 'village'."); } Object.Destroy((Object)(object)val); } internal List<string> <AddCustomCommands>b__0_11() { return new List<string> { "tower", "village" }; } internal void <AddCustomCommands>b__0_12(ConsoleEventArgs args) { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); return; } if (args.Length < 2 || !int.TryParse(args[1], out var result)) { args.Context.AddString("Usage: raiderclan_wave <waveNumber>"); return; } if (!RaiderEvents.IsRaidActive()) { RaiderEvents.StartRaidManually(); } MethodInfo methodInfo = AccessTools.Method(typeof(RaiderEvents), "SpawnWave", (Type[])null, (Type[])null); for (int i = 0; i < result; i++) { methodInfo.Invoke(null, null); } args.Context.AddString($"Spawned raid wave {result}"); } internal void <AddCustomCommands>b__0_13(ConsoleEventArgs args) { //IL_002a: 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) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); return; } Biome val = (Biome)1; if (args.Length >= 2 && Enum.TryParse<Biome>(args[1], ignoreCase: true, out Biome result)) { val = result; } Vector3 val2 = ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 2f; RaiderLoot.DropRegularLoot(val2, val); args.Context.AddString($"Spawned regular loot for {val} biome at {val2}"); } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] [HarmonyPostfix] private static void AddCustomCommands() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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_00de: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else { Biome val16 = (Biome)1; if (args.Length >= 2) { if (Enum.TryParse<Biome>(args[1], ignoreCase: true, out Biome result)) { val16 = result; } else { args.Context.AddString("Invalid biome: " + args[1] + ". Using Meadows."); } } bool result2 = false; if (args.Length >= 3) { bool.TryParse(args[2], out result2); } Vector3 val17 = ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 3f; Humanoid val18 = RaiderAI.SpawnRaider(val17, val16, result2); if ((Object)(object)val18 != (Object)null) { args.Context.AddString(string.Format("Spawned {0} for biome {1} at {2}", result2 ? "Chieftain" : "Raider", val16, val17)); RaiderClansPlugin.Logger.LogInfo((object)$"Dev command spawned raider: Biome={val16}, Chieftain={result2}, Pos={val17}"); } else { args.Context.AddString("Failed to spawn raider - check logs"); } } }; <>c.<>9__0_0 = val; obj = (object)val; } object obj2 = <>c.<>9__0_1; if (obj2 == null) { ConsoleOptionsFetcher val2 = () => new List<string> { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands" }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } new ConsoleCommand("raiderclan_spawn", "[biome] [isChieftain] - Spawn a test raider", (ConsoleEvent)obj, true, false, false, false, false, (ConsoleOptionsFetcher)obj2, false, false, false); object obj3 = <>c.<>9__0_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { //IL_004e: 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) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else if (args.Length >= 2) { if (Enum.TryParse<Biome>(args[1], ignoreCase: true, out Biome result)) { RaiderEvents.StartRaidManually(result); args.Context.AddString($"Raider clan raid event started for {result}!"); RaiderClansPlugin.Logger.LogInfo((object)$"Dev command started raid event for biome {result}"); } else { args.Context.AddString("Invalid biome '" + args[1] + "'."); } } else { RaiderEvents.StartRaidManually(); args.Context.AddString("Raider clan raid event started!"); RaiderClansPlugin.Logger.LogInfo((object)"Dev command started raid event"); } }; <>c.<>9__0_2 = val3; obj3 = (object)val3; } ConsoleEvent val4 = (ConsoleEvent)obj3; object obj4 = <>c.<>9__0_3; if (obj4 == null) { ConsoleOptionsFetcher val5 = () => new List<string> { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands" }; <>c.<>9__0_3 = val5; obj4 = (object)val5; } new ConsoleCommand("raiderclan_startraid", "[biome] - Start a raider clan raid event (optional biome override)", val4, true, false, false, false, false, (ConsoleOptionsFetcher)obj4, false, false, false); object obj5 = <>c.<>9__0_4; if (obj5 == null) { ConsoleOptionsFetcher val6 = () => new List<string> { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands" }; <>c.<>9__0_4 = val6; obj5 = (object)val6; } new ConsoleCommand("raidclan_startraid", "[biome] - Alias for raiderclan_startraid", val4, true, false, false, false, false, (ConsoleOptionsFetcher)obj5, false, false, false); object obj6 = <>c.<>9__0_5; if (obj6 == null) { ConsoleEvent val7 = delegate(ConsoleEventArgs args) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0046: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else { Vector2i zone = ZoneSystem.GetZone(((Component)Player.m_localPlayer).transform.position); args.Context.AddString($"Processing zone {zone}..."); RaiderClansPlugin.Logger.LogInfo((object)$"Dev command processing zone: {zone}"); int num = RaiderTowerOverwrites.ProcessZoneLocations(zone); args.Context.AddString($"Processed {num} locations in zone {zone}"); } }; <>c.<>9__0_5 = val7; obj6 = (object)val7; } new ConsoleCommand("raiderclan_processzone", "- Force process locations in current zone", (ConsoleEvent)obj6, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj7 = <>c.<>9__0_6; if (obj7 == null) { ConsoleEvent val8 = delegate(ConsoleEventArgs args) { if (args.Length >= 2) { if (args[1].ToLower() == "on") { RaiderClansPlugin.EnableDebugLogging.Value = true; args.Context.AddString("Debug logging enabled"); } else if (args[1].ToLower() == "off") { RaiderClansPlugin.EnableDebugLogging.Value = false; args.Context.AddString("Debug logging disabled"); } } else { args.Context.AddString("Debug logging is currently " + (RaiderClansPlugin.EnableDebugLogging.Value ? "enabled" : "disabled")); } }; <>c.<>9__0_6 = val8; obj7 = (object)val8; } new ConsoleCommand("raiderclan_debug", "[on/off] - Toggle debug logging", (ConsoleEvent)obj7, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj8 = <>c.<>9__0_7; if (obj8 == null) { ConsoleEvent val9 = delegate(ConsoleEventArgs args) { HashSet<string> processedLocations = RaiderTowerOverwrites.GetProcessedLocations(); args.Context.AddString($"Processed {processedLocations.Count} locations:"); foreach (string item in processedLocations) { args.Context.AddString(" - " + item); } }; <>c.<>9__0_7 = val9; obj8 = (object)val9; } new ConsoleCommand("raiderclan_listlocations", "- List all processed locations", (ConsoleEvent)obj8, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj9 = <>c.<>9__0_8; if (obj9 == null) { ConsoleEvent val10 = delegate(ConsoleEventArgs args) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) RaiderRole result; if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else if (args.Length < 2 || !Enum.TryParse<RaiderRole>(args[1], ignoreCase: true, out result)) { args.Context.AddString("Usage: raiderclan_spawnrole <Warrior|Pillager|Chieftain> [Biome]"); } else { Biome val16 = (Biome)1; if (args.Length >= 3 && Enum.TryParse<Biome>(args[2], ignoreCase: true, out Biome result2)) { val16 = result2; } Vector3 val17 = ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 3f; Humanoid val18 = RaiderAI.SpawnRaider(new RaiderAI.RaiderSpawnRequest(val17, val16, result)); args.Context.AddString(((Object)(object)val18 != (Object)null) ? $"Spawned {result} with {val16} loadout at {val17}" : "Failed to spawn raider"); } }; <>c.<>9__0_8 = val10; obj9 = (object)val10; } object obj10 = <>c.<>9__0_9; if (obj10 == null) { ConsoleOptionsFetcher val11 = () => new List<string> { "Warrior", "Pillager", "Chieftain" }; <>c.<>9__0_9 = val11; obj10 = (object)val11; } new ConsoleCommand("raiderclan_spawnrole", "<role> [biome] - Spawn a specific raider role with biome gear", (ConsoleEvent)obj9, true, false, false, false, false, (ConsoleOptionsFetcher)obj10, false, false, false); object obj11 = <>c.<>9__0_10; if (obj11 == null) { ConsoleEvent val12 = delegate(ConsoleEventArgs args) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else if (args.Length < 2) { args.Context.AddString("Usage: raiderclan_spawngarrison <tower|village> [radius]"); } else { string text = args[1].ToLowerInvariant(); float num = 20f; if (args.Length >= 3 && float.TryParse(args[2], out var result)) { num = Mathf.Clamp(result, 5f, 50f); } GameObject val16 = new GameObject("RaiderClans_GarrisonRoot"); val16.transform.position = ((Component)Player.m_localPlayer).transform.position; if (text == "tower") { RaiderTowerOverwrites.SpawnTowerRaiders(val16); args.Context.AddString($"Spawned tower garrison at {val16.transform.position} (radius {num})"); } else if (text == "village") { RaiderTowerOverwrites.SpawnVillageRaiders(val16); args.Context.AddString($"Spawned village garrison at {val16.transform.position} (radius {num})"); } else { args.Context.AddString("Invalid garrison type. Use 'tower' or 'village'."); } Object.Destroy((Object)(object)val16); } }; <>c.<>9__0_10 = val12; obj11 = (object)val12; } object obj12 = <>c.<>9__0_11; if (obj12 == null) { ConsoleOptionsFetcher val13 = () => new List<string> { "tower", "village" }; <>c.<>9__0_11 = val13; obj12 = (object)val13; } new ConsoleCommand("raiderclan_spawngarrison", "<tower|village> [radius] - Spawn a raider garrison using tower/village rules", (ConsoleEvent)obj11, true, false, false, false, false, (ConsoleOptionsFetcher)obj12, false, false, false); object obj13 = <>c.<>9__0_12; if (obj13 == null) { ConsoleEvent val14 = delegate(ConsoleEventArgs args) { int result; if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else if (args.Length < 2 || !int.TryParse(args[1], out result)) { args.Context.AddString("Usage: raiderclan_wave <waveNumber>"); } else { if (!RaiderEvents.IsRaidActive()) { RaiderEvents.StartRaidManually(); } MethodInfo methodInfo = AccessTools.Method(typeof(RaiderEvents), "SpawnWave", (Type[])null, (Type[])null); for (int i = 0; i < result; i++) { methodInfo.Invoke(null, null); } args.Context.AddString($"Spawned raid wave {result}"); } }; <>c.<>9__0_12 = val14; obj13 = (object)val14; } new ConsoleCommand("raiderclan_wave", "<waveNumber> - Force-spawn a raid wave", (ConsoleEvent)obj13, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj14 = <>c.<>9__0_13; if (obj14 == null) { ConsoleEvent val15 = delegate(ConsoleEventArgs args) { //IL_002a: 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) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { args.Context.AddString("No local player found"); } else { Biome val16 = (Biome)1; if (args.Length >= 2 && Enum.TryParse<Biome>(args[1], ignoreCase: true, out Biome result)) { val16 = result; } Vector3 val17 = ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 2f; RaiderLoot.DropRegularLoot(val17, val16); args.Context.AddString($"Spawned regular loot for {val16} biome at {val17}"); } }; <>c.<>9__0_13 = val15; obj14 = (object)val15; } new ConsoleCommand("raiderclan_spawnloot", "[biome] - Spawn infused loot item", (ConsoleEvent)obj14, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); RaiderClansPlugin.Logger.LogInfo((object)"RaiderClans dev commands registered"); } } [HarmonyPatch(typeof(Game), "FixedUpdate")] internal class GameFixedUpdatePatch { private static void Postfix(Game __instance) { RaiderEvents.Update(Time.fixedDeltaTime); } } [HarmonyPatch(typeof(Character), "OnDeath")] internal class CharacterOnDeathPatch { private static void Postfix(Character __instance) { bool flag = RaiderAI.IsRaider(__instance); if (!flag) { string text = __instance.m_name ?? string.Empty; flag = text.StartsWith("Clan ", StringComparison.OrdinalIgnoreCase) || ((Object)__instance).name.Contains("RaiderClan_Melee") || ((Object)__instance).name.Contains("RaiderClan_Ranged"); } bool flag2 = RaiderAI.IsChieftain(__instance) || __instance.m_name == "Clan Chieftain"; RaiderClansPlugin.LogDebug($"Character died: {((Object)__instance).name}, isRaider={flag}, isChieftain={flag2}"); if (flag) { RaiderEvents.OnRaiderKilled(__instance, identityConfirmed: true, flag2); } } } [HarmonyPatch(typeof(ItemData), "GetDamage", new Type[] { typeof(int), typeof(float) })] internal class ItemDataGetDamagePatch { private static void Postfix(ItemData __instance, ref DamageTypes __result) { float infusedDamageBonus = RaiderLoot.GetInfusedDamageBonus(__instance); if (infusedDamageBonus > 1f) { ((DamageTypes)(ref __result)).Modify(infusedDamageBonus); } } } [HarmonyPatch(typeof(ItemData), "GetArmor", new Type[] { typeof(int), typeof(float) })] internal class ItemDataGetArmorPatch { private static void Postfix(ItemData __instance, ref float __result) { float infusedArmorBonus = RaiderLoot.GetInfusedArmorBonus(__instance); if (infusedArmorBonus > 1f) { __result *= infusedArmorBonus; } } } [HarmonyPatch(typeof(Humanoid), "EquipItem", new Type[] { typeof(ItemData), typeof(bool) })] internal class HumanoidEquipItemPatch { private static void Postfix(Humanoid __instance, ItemData item, bool triggerEquipEffects) { if (!triggerEquipEffects || item == null) { return; } float infusedDamageBonus = RaiderLoot.GetInfusedDamageBonus(item); float infusedArmorBonus = RaiderLoot.GetInfusedArmorBonus(item); if (!(infusedDamageBonus > 1f) && !(infusedArmorBonus > 1f)) { return; } SEMan sEMan = ((Character)__instance).GetSEMan(); if (sEMan != null) { StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("Potion_hasty")); if ((Object)(object)statusEffect != (Object)null) { sEMan.AddStatusEffect(statusEffect, false, 0, 0f); } } } } [HarmonyPatch(typeof(Humanoid), "UnequipItem", new Type[] { typeof(ItemData), typeof(bool) })] internal class HumanoidUnequipItemPatch { private static void Postfix(Humanoid __instance, ItemData item, bool triggerEquipEffects) { if (!triggerEquipEffects || item == null) { return; } float infusedDamageBonus = RaiderLoot.GetInfusedDamageBonus(item); float infusedArmorBonus = RaiderLoot.GetInfusedArmorBonus(item); if (!(infusedDamageBonus > 1f) && !(infusedArmorBonus > 1f)) { return; } SEMan sEMan = ((Character)__instance).GetSEMan(); if (sEMan != null) { StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("Potion_hasty")); if ((Object)(object)statusEffect != (Object)null) { sEMan.RemoveStatusEffect(statusEffect, false); } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int) })] internal class ItemDataGetTooltipPatch { private static void Postfix(ItemData item, int qualityLevel, bool crafting, float worldLevel, int stackOverride, ref string __result) { if (item != null && (RaiderLoot.GetInfusedDamageBonus(item) > 1f || RaiderLoot.GetInfusedArmorBonus(item) > 1f)) { float infusedDamageBonus = RaiderLoot.GetInfusedDamageBonus(item); float infusedArmorBonus = RaiderLoot.GetInfusedArmorBonus(item); __result += "\n<color=orange>Infused</color>"; if (infusedDamageBonus > 1f) { int num = Mathf.RoundToInt((infusedDamageBonus - 1f) * 100f); __result += $"\n<color=yellow>+{num}% Damage</color>"; } if (infusedArmorBonus > 1f) { int num2 = Mathf.RoundToInt((infusedArmorBonus - 1f) * 100f); __result += $"\n<color=yellow>+{num2}% Armor</color>"; } __result += "\n<color=yellow>+25% Movement Speed</color>"; } } } [HarmonyPatch(typeof(Character), "HaveEitr")] internal class CharacterHaveEitrPatch { private static bool Prefix(Character __instance, ref bool __result) { if (RaiderAI.IsRaider(__instance)) { __result = true; return false; } return true; } } [HarmonyPatch(typeof(Character), "UseEitr")] internal class CharacterUseEitrPatch { private static bool Prefix(Character __instance) { if (RaiderAI.IsRaider(__instance)) { return false; } return true; } } [HarmonyPatch(typeof(Projectile), "FixedUpdate")] internal static class ProjectileFixedUpdatePatch { private static readonly FieldRef<Projectile, ZNetView> NviewRef = AccessTools.FieldRefAccess<Projectile, ZNetView>("m_nview"); private static readonly FieldRef<Projectile, Character> OwnerRef = AccessTools.FieldRefAccess<Projectile, Character>("m_owner"); private static readonly HashSet<int> LoggedProjectiles = new HashSet<int>(); private static void Prefix(Projectile __instance) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) ZNetView val = NviewRef.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.IsValid()) { return; } Character val2 = OwnerRef.Invoke(__instance); if (!((Object)(object)val2 == (Object)null) && RaiderAI.IsRaider(val2) && !val.IsOwner()) { int instanceID = ((Object)__instance).GetInstanceID(); if (LoggedProjectiles.Add(instanceID)) { ZDO zDO = val.GetZDO(); long num = ((zDO != null) ? zDO.GetOwner() : 0); long num2 = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0); RaiderClansPlugin.LogDebug($"[ProjectileDebug] Raider projectile not owned locally. owner={val2.m_name} projOwnerPeer={num} localPeer={num2} pos={((Component)__instance).transform.position}"); } } } } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class ProjectileOnHitPatch { private static readonly FieldRef<Projectile, Character> OwnerRef = AccessTools.FieldRefAccess<Projectile, Character>("m_owner"); private static readonly FieldRef<Projectile, HitData> OriginalHitDataRef = AccessTools.FieldRefAccess<Projectile, HitData>("m_originalHitData"); private static readonly FieldRef<Projectile, DamageTypes> DamageRef = AccessTools.FieldRefAccess<Projectile, DamageTypes>("m_damage"); private static void Prefix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water, Vector3 normal) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) Character val = OwnerRef.Invoke(__instance); if (!((Object)(object)val == (Object)null) && RaiderAI.IsRaider(val)) { string text = (Object.op_Implicit((Object)(object)collider) ? ((Object)collider).name : "<null>"); DamageTypes val2 = DamageRef.Invoke(__instance); float totalDamage = ((DamageTypes)(ref val2)).GetTotalDamage(); HitData obj = OriginalHitDataRef.Invoke(__instance); float num = ((obj != null) ? ((DamageTypes)(ref obj.m_damage)).GetTotalDamage() : 0f); RaiderClansPlugin.LogDebug($"[ProjectileDebug] OnHit owner={val.m_name} targetCollider={text} water={water} pos={hitPoint} projDamage={totalDamage:F2} originalDamage={num:F2}"); } } } [BepInPlugin("com.ruijven.raiderclans", "RaiderClans", "1.0.0")] internal class RaiderClansPlugin : BaseUnityPlugin { public const string PluginGUID = "com.ruijven.raiderclans"; public const string PluginName = "RaiderClans"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Logger; public static ConfigEntry<float> DailyRaidChance; public static ConfigEntry<float> RaidCheckTimeOfDay; public static ConfigEntry<bool> EnableTowerOverwrites; public static ConfigEntry<bool> EnableRaidEvents; public static ConfigEntry<bool> EnableDebugLogging; public static ConfigEntry<string> Wave1Composition; public static ConfigEntry<string> Wave2Composition; public static ConfigEntry<string> Wave3Composition; public static ConfigEntry<string> Wave4Composition; public static ConfigEntry<bool> EnableRegularLoot; public static ConfigEntry<bool> ChieftainDropInfusedItem; public static ConfigEntry<float> InfusedDamageBonus; public static ConfigEntry<float> InfusedArmorBonus; internal static RaiderClansPlugin Instance { get; private set; } private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; InitializeConfig(); Harmony val = new Harmony("com.ruijven.raiderclans"); val.PatchAll(Assembly.GetExecutingAssembly()); RaiderAI.Initialize(); RaiderTowerOverwrites.Initialize(); ((MonoBehaviour)this).StartCoroutine(DelayedInitialization()); Logger.LogInfo((object)"RaiderClans v1.0.0 loaded successfully!"); } private void OnDestroy() { RaiderTowerOverwrites.SaveProcessedLocations(); } private void InitializeConfig() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Expected O, but got Unknown //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Expected O, but got Unknown DailyRaidChance = ((BaseUnityPlugin)this).Config.Bind<float>("Raid Events", "DailyRaidChance", 0.15f, new ConfigDescription("Chance for a raid to trigger each day at the specified time (0.0 - 1.0, e.g., 0.15 = 15%)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); RaidCheckTimeOfDay = ((BaseUnityPlugin)this).Config.Bind<float>("Raid Events", "RaidCheckTimeOfDay", 0.6f, new ConfigDescription("Time of day to check for raid trigger (0.0 - 1.0, e.g., 0.6 = just after noon)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); EnableTowerOverwrites = ((BaseUnityPlugin)this).Config.Bind<bool>("Tower Overwrites", "EnableTowerOverwrites", true, new ConfigDescription("Enable Mistlands Dvergr tower overwrites with raiders", (AcceptableValueBase)null, Array.Empty<object>())); EnableRaidEvents = ((BaseUnityPlugin)this).Config.Bind<bool>("Raid Events", "EnableRaidEvents", true, new ConfigDescription("Enable custom raid event system", (AcceptableValueBase)null, Array.Empty<object>())); EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogging", false, new ConfigDescription("Enable verbose debug logging for troubleshooting", (AcceptableValueBase)null, Array.Empty<object>())); Wave1Composition = ((BaseUnityPlugin)this).Config.Bind<string>("Raid Waves", "Wave1", "Warrior:2", "Comma-separated Role:Count entries (e.g., Warrior:3,Pillager:1) for wave 1"); Wave2Composition = ((BaseUnityPlugin)this).Config.Bind<string>("Raid Waves", "Wave2", "Warrior:3,Pillager:1", "Comma-separated Role:Count entries (e.g., Warrior:3,Pillager:1) for wave 2"); Wave3Composition = ((BaseUnityPlugin)this).Config.Bind<string>("Raid Waves", "Wave3", "Warrior:4,Pillager:2", "Comma-separated Role:Count entries (e.g., Warrior:4,Pillager:2) for wave 3"); Wave4Composition = ((BaseUnityPlugin)this).Config.Bind<string>("Raid Waves", "Wave4", "Warrior:5,Pillager:3,Chieftain:1", "Comma-separated Role:Count entries (e.g., Warrior:5,Pillager:3,Chieftain:1) for wave 4"); Wave1Composition.SettingChanged += OnWaveConfigChanged; Wave2Composition.SettingChanged += OnWaveConfigChanged; Wave3Composition.SettingChanged += OnWaveConfigChanged; Wave4Composition.SettingChanged += OnWaveConfigChanged; ReloadWaveConfigFromSettings(); EnableRegularLoot = ((BaseUnityPlugin)this).Config.Bind<bool>("Loot - Regular Raiders", "EnableLoot", true, new ConfigDescription("Enable loot drops for regular raiders", (AcceptableValueBase)null, Array.Empty<object>())); ChieftainDropInfusedItem = ((BaseUnityPlugin)this).Config.Bind<bool>("Loot - Chieftains", "DropInfusedItem", true, new ConfigDescription("Whether chieftains drop infused items", (AcceptableValueBase)null, Array.Empty<object>())); InfusedDamageBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Loot - Chieftains", "InfusedDamageBonus", 1.2f, new ConfigDescription("Damage bonus multiplier for infused items (e.g., 1.2 = +20% damage)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>())); InfusedArmorBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Loot - Chieftains", "InfusedArmorBonus", 1.2f, new ConfigDescription("Armor bonus multiplier for infused items (e.g., 1.2 = +20% armor)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>())); void OnWaveConfigChanged(object _, EventArgs __) { ReloadWaveConfigFromSettings(); } } private IEnumerator DelayedInitialization() { while ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items.Count == 0) { yield return null; } RaiderLoot.Initialize(); Logger.LogInfo((object)"RaiderClans systems initialized successfully."); Logger.LogInfo((object)"Raider prefab will be created when ZNetScene loads."); } public static void LogDebug(string message) { if (EnableDebugLogging.Value) { Logger.LogInfo((object)("[DEBUG] " + message)); } } private void ReloadWaveConfigFromSettings() { RaiderEvents.ConfigureWaves(Wave1Composition?.Value, Wave2Composition?.Value, Wave3Composition?.Value, Wave4Composition?.Value); } } public class RaiderEvents { private sealed class RaidWaveDefinition { public int WaveNumber { get; } public Dictionary<RaiderRole, int> RoleCounts { get; } public RaidWaveDefinition(int waveNumber, Dictionary<RaiderRole, int> roleCounts) { WaveNumber = waveNumber; RoleCounts = roleCounts ?? new Dictionary<RaiderRole, int>(); } } private static bool raidActive = false; private static Vector3 raidPosition; private static Biome raidBiome; private static int currentWave = 0; private static int raidersKilled = 0; private static bool chieftainSpawned = false; private static List<Character> activeRaiders = new List<Character>(); private static float lastRaidCheckTime = -1f; private static float nextWaveTime = 0f; private const float WAVE_INTERVAL = 30f; private static RaidWaveDefinition[] s_waveDefinitions = DefaultWaves; private static readonly RaidWaveDefinition[] DefaultWaves = new RaidWaveDefinition[4] { new RaidWaveDefinition(1, new Dictionary<RaiderRole, int> { { RaiderRole.Warrior, 2 } }), new RaidWaveDefinition(2, new Dictionary<RaiderRole, int> { { RaiderRole.Warrior, 3 }, { RaiderRole.Pillager, 1 } }), new RaidWaveDefinition(3, new Dictionary<RaiderRole, int> { { RaiderRole.Warrior, 4 }, { RaiderRole.Pillager, 2 } }), new RaidWaveDefinition(4, new Dictionary<RaiderRole, int> { { RaiderRole.Warrior, 5 }, { RaiderRole.Pillager, 3 }, { RaiderRole.Chieftain, 1 } }) }; public static void StartRaidManually() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Biome highestUnlockedBiome = GetHighestUnlockedBiome(); StartRaidManually(highestUnlockedBiome); } public static void StartRaidManually(Biome biome) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { RaiderClansPlugin.Logger.LogWarning((object)"No local player found for manual raid start"); return; } if (raidActive) { RaiderClansPlugin.Logger.LogWarning((object)"Raid already active"); return; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; RaiderClansPlugin.Logger.LogInfo((object)$"Manually starting raid at {position}, biome: {biome}"); StartRaid(position, biome); } public static void Update(float dt) { if (RaiderClansPlugin.EnableRaidEvents.Value && ZNet.instance.IsServer()) { CheckDailyRaidTrigger(); UpdateRaidState(dt); } } private static void CheckDailyRaidTrigger() { float dayFraction = EnvMan.instance.GetDayFraction(); float value = RaiderClansPlugin.RaidCheckTimeOfDay.Value; if (lastRaidCheckTime < 0f || dayFraction < lastRaidCheckTime) { lastRaidCheckTime = dayFraction; } else if (dayFraction >= value && lastRaidCheckTime < value) { lastRaidCheckTime = dayFraction; if (Random.value <= RaiderClansPlugin.DailyRaidChance.Value) { StartRaid(); } } } private static void StartRaid() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if (raidActive) { RaiderClansPlugin.LogDebug("Raid already active, skipping StartRaid"); return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { RaiderClansPlugin.Logger.LogWarning((object)"No local player found for raid start"); return; } Biome biome = WorldGenerator.instance.GetBiome(((Component)localPlayer).transform.position); raidBiome = GetHighestUnlockedBiome(); raidPosition = ((Component)localPlayer).transform.position; raidActive = true; currentWave = 0; raidersKilled = 0; chieftainSpawned = false; activeRaiders.Clear(); nextWaveTime = Time.time; RaiderClansPlugin.Logger.LogInfo((object)$"Starting raid in biome: {raidBiome} at position {raidPosition}"); RaiderClansPlugin.LogDebug($"Player biome: {biome}, Raid biome: {raidBiome}"); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Raiders are attacking!", 0, (Sprite)null); } } private static void StartRaid(Vector3 position, Biome biome) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (raidActive) { RaiderClansPlugin.LogDebug("Raid already active, skipping StartRaid"); return; } raidBiome = biome; raidPosition = position; raidActive = true; currentWave = 0; raidersKilled = 0; chieftainSpawned = false; activeRaiders.Clear(); nextWaveTime = Time.time; RaiderClansPlugin.Logger.LogInfo((object)$"Starting raid in biome: {raidBiome} at position {raidPosition}"); } private static Biome GetHighestUnlockedBiome() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return (Biome)1; } if (instance.GetGlobalKey("defeated_queen")) { return (Biome)32; } if (instance.GetGlobalKey("defeated_bonemass")) { return (Biome)512; } if (instance.GetGlobalKey("defeated_goblinking")) { return (Biome)16; } if (instance.GetGlobalKey("defeated_dragon")) { return (Biome)4; } if (instance.GetGlobalKey("defeated_greydwarf")) { return (Biome)2; } if (instance.GetGlobalKey("defeated_eikthyr")) { return (Biome)8; } return (Biome)1; } private static void SpawnWave() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) RaidWaveDefinition[] waveDefinitions = GetWaveDefinitions(); int num = currentWave; if (num >= waveDefinitions.Length) { RaiderClansPlugin.LogDebug("No additional wave definitions available."); return; } RaidWaveDefinition raidWaveDefinition = waveDefinitions[num]; currentWave++; int num2 = 0; foreach (KeyValuePair<RaiderRole, int> roleCount in raidWaveDefinition.RoleCounts) { RaiderRole key = roleCount.Key; int num3 = Mathf.Max(0, roleCount.Value); for (int i = 0; i < num3; i++) { Vector3 distributedSpawnPosition = GetDistributedSpawnPosition(); Humanoid val = RaiderAI.SpawnRaider(new RaiderAI.RaiderSpawnRequest(distributedSpawnPosition, raidBiome, key)); if ((Object)(object)val == (Object)null) { continue; } Character component = ((Component)val).GetComponent<Character>(); if ((Object)(object)component != (Object)null) { activeRaiders.Add(component); } if (key == RaiderRole.Chieftain && !chieftainSpawned) { chieftainSpawned = true; if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "The Clan Chieftain has entered the fray!", 0, (Sprite)null); } RaiderClansPlugin.Logger.LogInfo((object)"Chieftain spawned with wave"); } num2++; } } RaiderClansPlugin.Logger.LogInfo((object)$"Wave {raidWaveDefinition.WaveNumber}: Spawned {num2} raiders"); } private static Vector3 GetDistributedSpawnPosition() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) float num = Random.Range(18f, 32f); float num2 = Random.Range(0f, MathF.PI * 2f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Cos(num2) * num, 0f, Mathf.Sin(num2) * num); return raidPosition + val; } private static void UpdateRaidState(float dt) { if (!raidActive) { return; } activeRaiders.RemoveAll((Character r) => (Object)(object)r == (Object)null || r.IsDead()); RaidWaveDefinition[] waveDefinitions = GetWaveDefinitions(); if (currentWave < waveDefinitions.Length && Time.time >= nextWaveTime) { SpawnWave(); if (currentWave < waveDefinitions.Length) { nextWaveTime = Time.time + 30f; } } if (chieftainSpawned) { Character val = activeRaiders.Find((Character r) => RaiderAI.IsChieftain(r)); if ((Object)(object)val == (Object)null || val.IsDead()) { MakeRaidersFlee(); EndRaid(); } } else if (currentWave >= waveDefinitions.Length && activeRaiders.Count == 0) { EndRaid(); } } public static void ConfigureWaves(params string[] waveDefinitions) { if (waveDefinitions == null || waveDefinitions.Length == 0) { s_waveDefinitions = DefaultWaves; RaiderClansPlugin.Logger.LogInfo((object)"Using default raid wave definitions."); return; } List<RaidWaveDefinition> list = new List<RaidWaveDefinition>(); for (int i = 0; i < waveDefinitions.Length; i++) { Dictionary<RaiderRole, int> roleCounts = ParseWaveDefinition(waveDefinitions[i], i); list.Add(new RaidWaveDefinition(i + 1, roleCounts)); } s_waveDefinitions = list.ToArray(); RaiderClansPlugin.Logger.LogInfo((object)"Raid wave definitions reloaded from configuration."); } private static RaidWaveDefinition[] GetWaveDefinitions() { return s_waveDefinitions ?? DefaultWaves; } private static Dictionary<RaiderRole, int> ParseWaveDefinition(string config, int fallbackIndex) { Dictionary<RaiderRole, int> dictionary = new Dictionary<RaiderRole, int>(); if (!string.IsNullOrWhiteSpace(config)) { string[] array = config.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (text2.Length == 0) { continue; } string[] array3 = text2.Split(new char[2] { ':', '=' }, StringSplitOptions.RemoveEmptyEntries); if (array3.Length == 2) { int result2; if (!Enum.TryParse<RaiderRole>(array3[0].Trim(), ignoreCase: true, out var result)) { RaiderClansPlugin.Logger.LogWarning((object)("Unknown raider role '" + array3[0] + "' in wave config '" + config + "'")); } else if (!int.TryParse(array3[1].Trim(), out result2) || result2 <= 0) { RaiderClansPlugin.Logger.LogWarning((object)$"Invalid count '{array3[1]}' for role '{result}' in wave config '{config}'"); } else if (dictionary.ContainsKey(result)) { dictionary[result] += result2; } else { dictionary[result] = result2; } } } } if (dictionary.Count == 0) { return CloneRoleCounts(DefaultWaves[Mathf.Clamp(fallbackIndex, 0, DefaultWaves.Length - 1)]); } return dictionary; } private static Dictionary<RaiderRole, int> CloneRoleCounts(RaidWaveDefinition definition) { Dictionary<RaiderRole, int> dictionary = new Dictionary<RaiderRole, int>(); foreach (KeyValuePair<RaiderRole, int> roleCount in definition.RoleCounts) { dictionary[roleCount.Key] = roleCount.Value; } return dictionary; } private static void MakeRaidersFlee() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) foreach (Character activeRaider in activeRaiders) { if ((Object)(object)activeRaider != (Object)null && !activeRaider.IsDead() && !RaiderAI.IsChieftain(activeRaider)) { BaseAI component = ((Component)activeRaider).GetComponent<BaseAI>(); if ((Object)(object)component != (Object)null) { component.Flee(0f, Vector3.zero); } } } } private static void EndRaid() { raidActive = false; currentWave = 0; raidersKilled = 0; chieftainSpawned = false; activeRaiders.Clear(); RaiderClansPlugin.Logger.LogInfo((object)"Raid ended"); } public static void OnRaiderKilled(Character raider, bool identityConfirmed = false, bool chieftainConfirmed = false) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)raider == (Object)null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } bool flag = identityConfirmed || RaiderAI.IsRaider(raider); if (!flag) { string text = raider.m_name ?? string.Empty; flag = text.StartsWith("Clan ", StringComparison.OrdinalIgnoreCase); } if (flag) { raidersKilled++; RaiderClansPlugin.Logger.LogInfo((object)$"Raider killed. Total: {raidersKilled}"); if (chieftainConfirmed || RaiderAI.IsChieftain(raider)) { RaiderLoot.DropInfusedItem(((Component)raider).transform.position, raidBiome); MakeRaidersFlee(); EndRaid(); } } } public static bool IsRaidActive() { return raidActive; } } [HarmonyPatch] internal class RaiderHarmonyPatches { private static bool IsRaider(Character character) { if ((Object)(object)character == (Object)null) { return false; } string name = ((Object)character).name; return name.Contains("RaiderClan_Melee") || name.Contains("RaiderClan_Ranged"); } [HarmonyPatch(typeof(Attack), "UseAmmo")] [HarmonyPrefix] private static bool UseAmmo_Prefix(Attack __instance, ref bool __result) { if ((Object)(object)__instance?.m_character != (Object)null && IsRaider((Character)(object)__instance.m_character)) { __result = true; return false; } return true; } [HarmonyPatch(typeof(Character), "Awake")] [HarmonyPostfix] private static void IdentityInjection_Postfix(Character __instance) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!IsRaider(__instance)) { return; } ZNetView nview = __instance.m_nview; if (nview != null) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set("RaiderClans_IsRaider", true); } } ZNetView nview2 = __instance.m_nview; ZDO val = ((nview2 != null) ? nview2.GetZDO() : null); if (val != null) { int num = val.GetInt("RaiderClans_Biome", 1); Biome val2 = (Biome)num; RaiderClansPlugin.LogDebug($"[AWAKE] Retrieved biome from ZDO: {val2} (int: {num})"); CharacterDrop component = ((Component)__instance).GetComponent<CharacterDrop>(); RaiderLoot.ConfigureCharacterDrop(component, val2); } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] [HarmonyPostfix] private static void PathfindingFallback_Postfix(MonsterAI __instance, float dt) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) Character component = ((Component)__instance).GetComponent<Character>(); if (IsRaider(component) && (Object)(object)__instance.m_targetCreature != (Object)null && !((BaseAI)__instance).HavePath(((Component)__instance.m_targetCreature).transform.position)) { Vector3 position = ((Component)__instance.m_targetCreature).transform.position; Vector3 position2 = ((Component)__instance).transform.position; Vector3 val = position - position2; val.y = 0f; ((Vector3)(ref val)).Normalize(); ((BaseAI)__instance).MoveTo(dt, position2 + val, 5f, ((BaseAI)__instance).IsAlerted()); } } [HarmonyPatch(typeof(Character), "OnRagdollCreated")] [HarmonyPrefix] private static bool SkipRagdoll_Prefix(Character __instance, Ragdoll ragdoll) { if (IsRaider(__instance)) { return false; } return true; } [HarmonyPatch(typeof(Humanoid), "EquipBestWeapon")] [HarmonyPrefix] private static bool PreventWeaponSwitching_Prefix(Humanoid __instance) { if ((Object)(object)__instance != (Object)null && IsRaider((Character)(object)__instance)) { return false; } return true; } [HarmonyPatch(typeof(Character), "SetVisible")] [HarmonyPrefix] private static void SetVisibleLogging_Prefix(Character __instance, bool visible) { if ((Object)(object)__instance != (Object)null && IsRaider(__instance)) { ZNetView nview = __instance.m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); RaiderClansPlugin.LogDebug($"[VISIBILITY] {((Object)__instance).name} SetVisible({visible}) HasOwner={((val != null) ? new bool?(val.HasOwner()) : ((bool?)null))} Owner={((val != null) ? new long?(val.GetOwner()) : ((long?)null))} IsOwner={((val != null) ? new bool?(val.IsOwner()) : ((bool?)null))} IsValid={((val != null) ? new bool?(val.IsValid()) : ((bool?)null))}"); } } [HarmonyPatch(typeof(BaseAI), "FindEnemy")] [HarmonyPrefix] private static bool EnforceStructurePriority_Prefix(BaseAI __instance, ref Character __result) { MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null); if (val != null) { PillagerBehavior component = ((Component)val).GetComponent<PillagerBehavior>(); if ((Object)(object)component != (Object)null && component.ShouldPreferStructureTarget()) { __result = null; return false; } } return true; } } public class RaiderLoot { private const string InfusedDamageKey = "RaiderClans_InfusedDamage"; private const string InfusedArmorKey = "RaiderClans_InfusedArmor"; private static Dictionary<Biome, List<string>> biomeMaterialDrops; private static Dictionary<Biome, string> biomeRareCores; public static void ConfigureCharacterDrop(CharacterDrop charDrop, Biome biome) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL