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 SunnfjordheimModularv1 v0.0.1
SunnfjordheimModularv1.dll
Decompiled a week 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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using ServerSync; using SunnfjordheimModularv1; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; using sunnfjordheimmodular; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SunnfjordheimModularv1")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Azathoth")] [assembly: AssemblyProduct("SunnfjordheimModularv1")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("0.0.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { private readonly string <Name>k__BackingField; public string Name => <Name>k__BackingField; public ExtensionMarkerAttribute(string name) { <Name>k__BackingField = name; } } } namespace sunnfjordheimmodular { internal static class sunnfjordheimmodularPlugin { internal enum Toggle { On = 1, Off = 0 } internal const string ModGUID = "Azathoth.SunnfjordheimModularv1"; internal static CustomSyncedValue<string> SyncedDefinitions; internal static ConfigEntry<Toggle> Enabled; internal static ConfigEntry<Toggle> DebugLogging; internal static ConfigEntry<float> BossCreditRange; internal static ConfigEntry<int> BaseCommandCap; internal static ConfigEntry<int> EikthyrCommandCap; internal static ConfigEntry<int> ElderCommandCap; internal static ConfigEntry<int> BonemassCommandCap; internal static ConfigEntry<int> ModerCommandCap; internal static ConfigEntry<int> YagluthCommandCap; internal static ConfigEntry<int> QueenCommandCap; internal static ConfigEntry<int> FaderCommandCap; internal static ConfigEntry<string> CustomPersonalCommandKeys; internal static ConfigEntry<float> CommandRadius; internal static ConfigEntry<float> MinimumCommandCenterDistance; internal static ConfigEntry<int> BaseSettlementMilitaryCap; internal static ConfigEntry<int> BaseSettlementBarracksLimit; internal static ConfigEntry<int> MilitaryBannerCommandBonus; internal static ConfigEntry<int> LogisticsBannerBarracksBonus; internal static ConfigEntry<Toggle> DefaultGuildManagement; internal static ConfigEntry<string> CommandBannerSourcePrefab; internal static ConfigEntry<string> MilitaryBannerSourcePrefab; internal static ConfigEntry<string> LogisticsBannerSourcePrefab; internal static ConfigEntry<string> GenericBarracksSourcePrefab; internal static ConfigEntry<string> CommandBannerBuildCosts; internal static ConfigEntry<string> MilitaryBannerBuildCosts; internal static ConfigEntry<string> LogisticsBannerBuildCosts; internal static ConfigEntry<string> GenericBarracksBuildCosts; internal static ConfigEntry<string> GeneralBarracksBuildCosts; internal static ConfigEntry<float> BarracksResupplyRadius; internal static ConfigEntry<float> ArmoryLinkRadius; internal static ConfigEntry<Toggle> TgwIntegration; internal static ConfigEntry<Toggle> TgwSkipDecay; internal static ConfigEntry<Toggle> AutoPortraits; internal static ConfigEntry<int> PortraitResolution; private static FileSystemWatcher _definitionWatcher; private static bool _initialized; private static SunnfjordheimModularv1Plugin _hostPlugin; internal static ManualLogSource Log => SunnfjordheimModularv1Plugin.SunnfjordheimModularv1Logger; internal static ConfigSync ConfigSync { get; private set; } internal static bool IsEnabled => Enabled != null && Enabled.Value == Toggle.On; internal static bool IsDebug => DebugLogging != null && DebugLogging.Value == Toggle.On; internal static void Initialize(SunnfjordheimModularv1Plugin plugin) { if (_initialized || (Object)(object)plugin == (Object)null) { return; } _initialized = true; _hostPlugin = plugin; ConfigSync = SunnfjordheimModularv1Plugin.RTSConfigSync; BindConfiguration(((BaseUnityPlugin)plugin).Config); RTSDefinitionRegistry.EnsureDefaultDefinitionsFile(); if (ConfigSync != null) { SyncedDefinitions = new CustomSyncedValue<string>(ConfigSync, "RTSDefinitions", ""); SyncedDefinitions.ValueChanged += delegate { try { if (!ConfigSync.IsSourceOfTruth) { RTSDefinitionRegistry.ApplySyncedText(SyncedDefinitions.Value ?? ""); } } catch (Exception ex) { Log.LogWarning((object)("[RTS] Error aplicando definiciones sincronizadas: " + ex.Message)); } }; } RTSDefinitionRegistry.LoadFromDisk(); RTSRuntimeHost rTSRuntimeHost = ((Component)plugin).gameObject.GetComponent<RTSRuntimeHost>(); if ((Object)(object)rTSRuntimeHost == (Object)null) { rTSRuntimeHost = ((Component)plugin).gameObject.AddComponent<RTSRuntimeHost>(); } Object.DontDestroyOnLoad((Object)(object)((Component)rTSRuntimeHost).gameObject); SetupDefinitionWatcher(); Log.LogInfo((object)("[RTS ADVANCED] Inicializado sobre la base limpia. " + RTSDefinitionRegistry.UnitCount + " unidades / " + RTSDefinitionRegistry.BarracksCount + " perfiles de barracón.")); } internal static void Shutdown() { try { _definitionWatcher?.Dispose(); } catch { } _definitionWatcher = null; } private static void BindConfiguration(ConfigFile config) { Enabled = Bind(config, "RTS 1 - General", "Enabled", Toggle.On, "Activa o desactiva el sistema RTS."); DebugLogging = Bind(config, "RTS 1 - General", "Debug Logging", Toggle.Off, "Muestra diagnóstico adicional del RTS.", synchronized: false); BaseCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "00 - Base", 5, "Capacidad personal antes de derrotar jefes."); EikthyrCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "01 - Eikthyr", 8, "Capacidad personal tras crédito personal de Eikthyr."); ElderCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "02 - Elder", 12, "Capacidad personal tras crédito personal de Elder."); BonemassCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "03 - Bonemass", 16, "Capacidad personal tras crédito personal de Bonemass."); ModerCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "04 - Moder", 20, "Capacidad personal tras crédito personal de Moder."); YagluthCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "05 - Yagluth", 25, "Capacidad personal tras crédito personal de Yagluth."); QueenCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "06 - Queen", 30, "Capacidad personal tras crédito personal de Queen."); FaderCommandCap = Bind(config, "RTS 2 - Personal Command Capacity", "07 - Fader", 35, "Capacidad personal tras crédito personal de Fader."); CustomPersonalCommandKeys = Bind(config, "RTS 2 - Personal Command Capacity", "08 - Custom Personal Keys", "", "Overrides opcionales formato key:capacidad,key2:capacidad. También revisa VV_PrivateKeys."); BossCreditRange = Bind(config, "RTS 2 - Personal Command Capacity", "Boss Credit Range", 100f, "Radio para recibir crédito personal por muerte de jefe."); CommandRadius = Bind(config, "RTS 3 - Settlement Command", "Command Banner Radius", 200f, "Radio del asentamiento creado por el Estandarte de Mando."); MinimumCommandCenterDistance = Bind(config, "RTS 3 - Settlement Command", "Minimum Same-Affiliation Center Distance", 350f, "Distancia mínima entre centros de la misma afiliación."); BaseSettlementMilitaryCap = Bind(config, "RTS 3 - Settlement Command", "Base Military Capacity", 30, "Capacidad militar compartida inicial de la base."); BaseSettlementBarracksLimit = Bind(config, "RTS 3 - Settlement Command", "Base Barracks Limit", 2, "Cantidad inicial máxima de barracones registrados."); MilitaryBannerCommandBonus = Bind(config, "RTS 3 - Settlement Command", "Military Banner Command Bonus", 20, "Capacidad militar extra del Estandarte Militar."); LogisticsBannerBarracksBonus = Bind(config, "RTS 3 - Settlement Command", "Logistics Banner Barracks Bonus", 1, "Barracón adicional permitido por Estandarte Logístico."); DefaultGuildManagement = Bind(config, "RTS 3 - Settlement Command", "Guild Management By Default", Toggle.Off, "Permite gestión automática por guild cuando TameGuildWars puede resolverlo."); CommandBannerSourcePrefab = Bind(config, "RTS 4 - Banner Clones", "Command Banner Source", "piece_banner01", "Prefab fuente clonado para RTS_CommandBanner."); MilitaryBannerSourcePrefab = Bind(config, "RTS 4 - Banner Clones", "Military Banner Source", "piece_banner02", "Prefab fuente clonado para RTS_MilitaryBanner."); LogisticsBannerSourcePrefab = Bind(config, "RTS 4 - Banner Clones", "Logistics Banner Source", "piece_banner03", "Prefab fuente clonado para RTS_LogisticsBanner."); GenericBarracksSourcePrefab = Bind(config, "RTS 4 - Banner Clones", "Generic Barracks Source", "piece_banner04", "Prefab fuente clonado para RTS_GenericBarracks de prueba/configurable."); CommandBannerBuildCosts = Bind(config, "RTS 4 - Banner Clones", "Command Banner Costs", "Wood:20,Coins:50", "Costes de construcción Prefab:Amount,Prefab:Amount."); MilitaryBannerBuildCosts = Bind(config, "RTS 4 - Banner Clones", "Military Banner Costs", "FineWood:20,Iron:5,Coins:100", "Costes del Estandarte Militar."); LogisticsBannerBuildCosts = Bind(config, "RTS 4 - Banner Clones", "Logistics Banner Costs", "Wood:30,Iron:5", "Costes del Estandarte Logístico."); GenericBarracksBuildCosts = Bind(config, "RTS 4 - Banner Clones", "Generic Barracks Costs", "Wood:40,Stone:10", "Costes del barracón configurable de prueba."); GeneralBarracksBuildCosts = Bind(config, "RTS 4 - Banner Clones", "General Barracks Costs", "Wood:40,Stone:10", "Costes del Barracón General que recluta RTS_HumanSettler."); BarracksResupplyRadius = Bind(config, "RTS 5 - Barracks & Logistics", "Barracks Resupply Radius", 12f, "Distancia para reabastecer munición desde el barracón/armería."); ArmoryLinkRadius = Bind(config, "RTS 5 - Barracks & Logistics", "Armory Link Radius", 10f, "Radio para vincular un cofre cercano como armería."); TgwIntegration = Bind(config, "RTS 6 - Compatibility", "TameGuildWars Integration", Toggle.On, "Usa TameGuildWars por reflexión si está instalado."); TgwSkipDecay = Bind(config, "RTS 6 - Compatibility", "TameGuildWars Skip Decay", Toggle.On, "Evita pérdida de obediencia de las tropas RTS cuando TGW está disponible."); AutoPortraits = Bind(config, "RTS 7 - UI", "Automatic 3D Portraits", Toggle.On, "Genera retratos 3D cacheados cuando no hay icono custom.", synchronized: false); PortraitResolution = Bind(config, "RTS 7 - UI", "Portrait Resolution", 256, "Resolución de retratos 3D (64-512).", synchronized: false); } private static ConfigEntry<T> Bind<T>(ConfigFile config, string group, string name, T value, string description, bool synchronized = true) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description + (synchronized ? " [Synced with Server]" : " [Local]"), (AcceptableValueBase)null, Array.Empty<object>()); ConfigEntry<T> val2 = config.Bind<T>(group, name, value, val); if (ConfigSync != null) { SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2); syncedConfigEntry.SynchronizedConfig = synchronized; } return val2; } private static void SetupDefinitionWatcher() { try { string definitionsPath = RTSDefinitionRegistry.DefinitionsPath; string directoryName = Path.GetDirectoryName(definitionsPath); string fileName = Path.GetFileName(definitionsPath); if (!string.IsNullOrWhiteSpace(directoryName) && !string.IsNullOrWhiteSpace(fileName)) { _definitionWatcher = new FileSystemWatcher(directoryName, fileName) { NotifyFilter = (NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime), IncludeSubdirectories = false, SynchronizingObject = ThreadingHelper.SynchronizingObject, EnableRaisingEvents = true }; _definitionWatcher.Changed += delegate { RTSDefinitionRegistry.RequestReload(); }; _definitionWatcher.Created += delegate { RTSDefinitionRegistry.RequestReload(); }; _definitionWatcher.Renamed += delegate { RTSDefinitionRegistry.RequestReload(); }; } } catch (Exception ex) { Log.LogWarning((object)("[RTS] Watcher de definiciones desactivado: " + ex.Message)); } } internal static void Debug(string message) { if (IsDebug) { Log.LogInfo((object)("[RTS] " + message)); } } } internal sealed class RTSCost { internal string Prefab = ""; internal int Amount; } internal enum RTSUnitMode { ReadyPrefab, HumanoidRecruit, PlayerCloneRecruit } internal sealed class RTSUnitDefinition { internal string Id = ""; internal bool Enabled = true; internal RTSUnitMode Mode = RTSUnitMode.ReadyPrefab; internal string Prefab = ""; internal string DisplayName = ""; internal string DisplayNameEnglish = ""; internal int CommandCost = 1; internal float RecruitTime = 30f; internal readonly List<RTSCost> RecruitCosts = new List<RTSCost>(); internal readonly List<RTSCost> Loadout = new List<RTSCost>(); internal bool RequireArmoryLoadout = true; internal bool DropEquipmentOnDeath = true; internal bool CustomizeAppearance = true; internal readonly List<string> RecruitNames = new List<string>(); internal readonly List<string> HairOptions = new List<string>(); internal readonly List<string> BeardOptions = new List<string>(); internal string AmmoItem = ""; internal int AmmoCapacity; internal int AmmoPerAttack = 1; internal float PortraitZoom = 1f; internal float PortraitYOffset; internal float PortraitYaw; internal string LocalizedDisplayName => RTSUtil.T(DisplayName, string.IsNullOrWhiteSpace(DisplayNameEnglish) ? DisplayName : DisplayNameEnglish); } internal sealed class RTSBarracksDefinition { internal string Id = ""; internal bool Enabled = true; internal string Prefab = ""; internal bool ProfileOnly; internal string DisplayName = ""; internal string DisplayNameEnglish = ""; internal bool AllowRename = true; internal bool AllowProfileChange; internal readonly List<string> SelectableProfiles = new List<string>(); internal readonly List<RTSCost> BuildCosts = new List<RTSCost>(); internal int LocalCommandLimit = 10; internal int QueueLimit = 3; internal int MaxPerSettlement = 0; internal Vector3 SpawnOffset = new Vector3(0f, 0f, 3f); internal readonly List<string> UnitIds = new List<string>(); internal string LocalizedDisplayName => RTSUtil.T(DisplayName, string.IsNullOrWhiteSpace(DisplayNameEnglish) ? DisplayName : DisplayNameEnglish); } internal static class RTSDefinitionRegistry { private static readonly Dictionary<string, RTSUnitDefinition> Units = new Dictionary<string, RTSUnitDefinition>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, RTSBarracksDefinition> Barracks = new Dictionary<string, RTSBarracksDefinition>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, RTSBarracksDefinition> BarracksByPrefab = new Dictionary<string, RTSBarracksDefinition>(StringComparer.OrdinalIgnoreCase); private static bool _reloadRequested; private static float _reloadNotBefore; internal static string DefinitionsPath => Path.Combine(Paths.ConfigPath, "Azathoth.SunnfjordheimModularv1.RTSDefinitions.cfg"); internal static int UnitCount => Units.Count; internal static int BarracksCount => Barracks.Count; internal static IEnumerable<RTSBarracksDefinition> AllBarracks => Barracks.Values; internal static IEnumerable<RTSBarracksDefinition> AllPhysicalBarracks => Barracks.Values.Where((RTSBarracksDefinition x) => x != null && !x.ProfileOnly && !string.IsNullOrWhiteSpace(x.Prefab)); internal static string DefaultDefinitionsText => "# =============================================================\n# SunnfjordheimModularv1 RTS PRO 1.2.2 - DEFINITIONS\n# =============================================================\n# The ID is the text after Unit. or Barracks. and is INTERNAL to RTS.\n# Prefab is the REAL prefab registered by Valheim/another mod/MonsterDB.\n# Costs/List syntax: Prefab:Amount,Prefab:Amount\n# SpawnOffset: X,Y,Z local to the physical barracks.\n# DisplayName is the Spanish/fallback name; DisplayNameEnglish is shown in English.\n#\n# UNIT MODES\n# ReadyPrefab = spawn the creature exactly as it already exists.\n# HumanoidRecruit = spawn an existing Humanoid prefab and equip Loadout.\n# PlayerCloneRecruit = spawn RTS_HumanSettler, a registered clone of Valheim Player\n# with the real Player body/VisEquipment plus NPC AI.\n#\n# BARRACKS\n# A normal [Barracks.X] with Prefab is a FIXED physical barracks.\n# A ProfileOnly barracks has no physical prefab and can be selected by a\n# generic host through SelectableProfiles.\n# =============================================================\n\n\n# Ready general human resident. No external humanoid prefab is required.\n[Unit.GeneralHuman]\nEnabled = true\nMode = PlayerCloneRecruit\nPrefab = RTS_HumanSettler\nDisplayName = Colono Humano\nDisplayNameEnglish = Human Settler\nCommandCost = 1\nRecruitTime = 20\nRecruitCosts = Coins:25\nLoadout =\nRequireArmoryLoadout = false\nDropEquipmentOnDeath = true\nCustomizeAppearance = true\nNames = Erik,Bjorn,Leif,Ulf,Runa,Freya,Astrid,Sigrid,Ingrid,Harald,Einar,Liv\nHairOptions =\nBeardOptions =\nAmmoItem =\nAmmoCapacity = 0\nAmmoPerAttack = 0\n\n[Unit.CloneTrooper]\nEnabled = true\nMode = ReadyPrefab\nPrefab = STA_ClonTrooper\nDisplayName = Soldado Clon\nDisplayNameEnglish = Clone Trooper\nCommandCost = 1\nRecruitTime = 30\nRecruitCosts = Coins:50,Iron:2\nAmmoItem = ArrowWood\nAmmoCapacity = 30\nAmmoPerAttack = 1\nPortraitZoom = 1.00\nPortraitYOffset = 0.00\nPortraitYaw = 0\n\n[Unit.EwokWarrior]\nEnabled = true\nMode = ReadyPrefab\nPrefab = STA_Ewook\nDisplayName = Guerrero Ewok\nDisplayNameEnglish = Ewok Warrior\nCommandCost = 1\nRecruitTime = 20\nRecruitCosts = Coins:25,Wood:10\nAmmoItem =\nAmmoCapacity = 0\nAmmoPerAttack = 0\nPortraitZoom = 1.00\nPortraitYOffset = 0.00\nPortraitYaw = 0\n\n# Example humanoid recruit. Replace the prefab with a real Humanoid prefab.\n[Unit.HumanGuard]\nEnabled = false\nMode = HumanoidRecruit\nPrefab = Dverger\nDisplayName = Guardia Equipable\nDisplayNameEnglish = Equipable Guard\nCommandCost = 1\nRecruitTime = 35\nRecruitCosts = Coins:60\nLoadout = SwordIron:1,ShieldBanded:1,HelmetIron:1,ArmorIronChest:1\nRequireArmoryLoadout = true\nDropEquipmentOnDeath = true\nCustomizeAppearance = true\nNames = Erik,Bjorn,Leif,Ulf,Runa,Freya,Astrid,Sigrid\n# Leave HairOptions/BeardOptions blank to auto-discover loaded vanilla/custom options.\nHairOptions =\nBeardOptions =\nAmmoItem =\nAmmoCapacity = 0\nAmmoPerAttack = 0\n\n# FIXED BARRACKS: every instance of the physical prefab uses this profile.\n\n# GENERAL BARRACKS: ready immediately for Hearthfolk-style human residents.\n[Barracks.GeneralHuman]\nEnabled = true\nPrefab = RTS_GeneralBarracks\nProfileOnly = false\nDisplayName = Barracón General\nDisplayNameEnglish = General Barracks\nAllowRename = true\nAllowProfileChange = false\nBuildCosts = Wood:40,Stone:10\nUnits = GeneralHuman\nLocalCommandLimit = 12\nQueueLimit = 4\nMaxPerSettlement = 2\nSpawnOffset = 0,0,4\n\n[Barracks.CloneBarracks]\nEnabled = true\nPrefab = STA_CloneBarracks\nProfileOnly = false\nDisplayName = Cuartel de la Republica\nDisplayNameEnglish = Republic Barracks\nAllowRename = true\nAllowProfileChange = false\nBuildCosts = Wood:50,Stone:20,Iron:5\nUnits = CloneTrooper\nLocalCommandLimit = 10\nQueueLimit = 3\nMaxPerSettlement = 2\nSpawnOffset = 0,0,4\n\n[Barracks.EwokVillage]\nEnabled = true\nPrefab = STA_EwokHut\nProfileOnly = false\nDisplayName = Aldea Ewok\nDisplayNameEnglish = Ewok Village\nAllowRename = true\nAllowProfileChange = false\nBuildCosts = Wood:40,RoundLog:10\nUnits = EwokWarrior\nLocalCommandLimit = 6\nQueueLimit = 2\nMaxPerSettlement = 2\nSpawnOffset = 0,0,3\n\n# PROFILE-ONLY examples for a GENERIC physical barracks.\n\n[Barracks.ProfileHumans]\nEnabled = true\nProfileOnly = true\nDisplayName = Perfil Humanos\nDisplayNameEnglish = Human Profile\nUnits = GeneralHuman\nLocalCommandLimit = 12\nQueueLimit = 4\nMaxPerSettlement = 2\nSpawnOffset = 0,0,4\n\n[Barracks.ProfileRepublic]\nEnabled = true\nProfileOnly = true\nDisplayName = Perfil Republica\nDisplayNameEnglish = Republic Profile\nUnits = CloneTrooper\nLocalCommandLimit = 10\nQueueLimit = 3\nMaxPerSettlement = 2\nSpawnOffset = 0,0,4\n\n[Barracks.ProfileEndor]\nEnabled = true\nProfileOnly = true\nDisplayName = Perfil Endor\nDisplayNameEnglish = Endor Profile\nUnits = EwokWarrior\nLocalCommandLimit = 6\nQueueLimit = 2\nMaxPerSettlement = 2\nSpawnOffset = 0,0,3\n\n# GENERIC HOST de prueba: el mod clona piece_banner04 como RTS_GenericBarracks.\n# Puedes cambiarlo por otro Piece real cuando quieras.\n# On first E interaction the commander chooses one of SelectableProfiles.\n[Barracks.GenericHost]\nEnabled = true\nPrefab = RTS_GenericBarracks\nProfileOnly = false\nDisplayName = Barracon Configurable\nDisplayNameEnglish = Configurable Barracks\nAllowRename = true\nAllowProfileChange = true\nSelectableProfiles = ProfileHumans,ProfileRepublic,ProfileEndor\nBuildCosts = Wood:60,Stone:30\nUnits =\nLocalCommandLimit = 1\nQueueLimit = 1\nMaxPerSettlement = 0\nSpawnOffset = 0,0,4\n"; internal static void EnsureDefaultDefinitionsFile() { if (File.Exists(DefinitionsPath)) { return; } try { File.WriteAllText(DefinitionsPath, DefaultDefinitionsText); } catch (Exception ex) { sunnfjordheimmodularPlugin.Log.LogError((object)("Could not create RTS definitions file: " + ex.Message)); } } internal static void RequestReload() { _reloadRequested = true; _reloadNotBefore = Time.unscaledTime + 0.5f; } internal static void TickReload() { if (_reloadRequested && !(Time.unscaledTime < _reloadNotBefore)) { _reloadRequested = false; if (sunnfjordheimmodularPlugin.ConfigSync.IsSourceOfTruth) { LoadFromDisk(); } else { ApplySyncedText(sunnfjordheimmodularPlugin.SyncedDefinitions?.Value ?? ""); } RTSPortraitCache.Clear(); RTSPieceCostOverrides.ClearCache(); sunnfjordheimmodularPlugin.Log.LogInfo((object)$"RTS definitions reloaded: {UnitCount} units / {BarracksCount} barracks profiles/hosts."); } } internal static void LoadFromDisk() { if (File.Exists(DefinitionsPath)) { string text = File.ReadAllText(DefinitionsPath); ApplySyncedText(text); if (sunnfjordheimmodularPlugin.SyncedDefinitions != null && sunnfjordheimmodularPlugin.ConfigSync.IsSourceOfTruth) { sunnfjordheimmodularPlugin.SyncedDefinitions.Value = text; } } } internal static void ApplySyncedText(string text) { Units.Clear(); Barracks.Clear(); BarracksByPrefab.Clear(); Dictionary<string, Dictionary<string, string>> dictionary = ParseIniText(text ?? ""); foreach (KeyValuePair<string, Dictionary<string, string>> item in dictionary) { string key = item.Key; Dictionary<string, string> value = item.Value; if (key.StartsWith("Unit.", StringComparison.OrdinalIgnoreCase)) { string text2 = key.Substring("Unit.".Length).Trim(); RTSUnitDefinition rTSUnitDefinition = ParseUnit(text2, value); if (rTSUnitDefinition != null && rTSUnitDefinition.Enabled && !string.IsNullOrWhiteSpace(rTSUnitDefinition.Prefab)) { Units[text2] = rTSUnitDefinition; } } else if (key.StartsWith("Barracks.", StringComparison.OrdinalIgnoreCase)) { string text3 = key.Substring("Barracks.".Length).Trim(); RTSBarracksDefinition rTSBarracksDefinition = ParseBarracks(text3, value); if (rTSBarracksDefinition != null && rTSBarracksDefinition.Enabled) { Barracks[text3] = rTSBarracksDefinition; } } } EnsureBuiltInGeneralHumanDefinitions(); foreach (RTSBarracksDefinition value3 in Barracks.Values) { value3.UnitIds.RemoveAll((string id) => !Units.ContainsKey(id)); value3.SelectableProfiles.RemoveAll((string id) => !Barracks.TryGetValue(id, out RTSBarracksDefinition value2) || value2 == null); if (!value3.ProfileOnly && !string.IsNullOrWhiteSpace(value3.Prefab)) { string text4 = RTSUtil.CleanPrefabName(value3.Prefab); if (!BarracksByPrefab.ContainsKey(text4)) { BarracksByPrefab[text4] = value3; continue; } sunnfjordheimmodularPlugin.Log.LogWarning((object)("RTSDefinitions: more than one physical Barracks section uses prefab '" + text4 + "'. Only '" + BarracksByPrefab[text4].Id + "' will be attached automatically.")); } } } private static void EnsureBuiltInGeneralHumanDefinitions() { //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) if (!Units.ContainsKey("GeneralHuman")) { RTSUnitDefinition rTSUnitDefinition = new RTSUnitDefinition { Id = "GeneralHuman", Enabled = true, Mode = RTSUnitMode.PlayerCloneRecruit, Prefab = "RTS_HumanSettler", DisplayName = "Colono Humano", DisplayNameEnglish = "Human Settler", CommandCost = 1, RecruitTime = 20f, RequireArmoryLoadout = false, DropEquipmentOnDeath = true, CustomizeAppearance = true }; rTSUnitDefinition.RecruitCosts.Add(new RTSCost { Prefab = "Coins", Amount = 25 }); string[] array = new string[12] { "Erik", "Bjorn", "Leif", "Ulf", "Runa", "Freya", "Astrid", "Sigrid", "Ingrid", "Harald", "Einar", "Liv" }; foreach (string item in array) { rTSUnitDefinition.RecruitNames.Add(item); } Units[rTSUnitDefinition.Id] = rTSUnitDefinition; } if (!Barracks.ContainsKey("GeneralHuman")) { RTSBarracksDefinition rTSBarracksDefinition = new RTSBarracksDefinition { Id = "GeneralHuman", Enabled = true, Prefab = "RTS_GeneralBarracks", ProfileOnly = false, DisplayName = "Barracón General", DisplayNameEnglish = "General Barracks", AllowRename = true, AllowProfileChange = false, LocalCommandLimit = 12, QueueLimit = 4, MaxPerSettlement = 2, SpawnOffset = new Vector3(0f, 0f, 4f) }; rTSBarracksDefinition.UnitIds.Add("GeneralHuman"); Barracks[rTSBarracksDefinition.Id] = rTSBarracksDefinition; } if (!Barracks.ContainsKey("ProfileHumans")) { RTSBarracksDefinition rTSBarracksDefinition2 = new RTSBarracksDefinition { Id = "ProfileHumans", Enabled = true, Prefab = "", ProfileOnly = true, DisplayName = "Perfil Humanos", DisplayNameEnglish = "Human Profile", AllowRename = true, AllowProfileChange = false, LocalCommandLimit = 12, QueueLimit = 4, MaxPerSettlement = 2, SpawnOffset = new Vector3(0f, 0f, 4f) }; rTSBarracksDefinition2.UnitIds.Add("GeneralHuman"); Barracks[rTSBarracksDefinition2.Id] = rTSBarracksDefinition2; } if (Barracks.TryGetValue("GenericHost", out RTSBarracksDefinition value) && value != null && !value.SelectableProfiles.Contains<string>("ProfileHumans", StringComparer.OrdinalIgnoreCase)) { value.SelectableProfiles.Insert(0, "ProfileHumans"); } } internal static bool TryGetUnit(string id, out RTSUnitDefinition definition) { return Units.TryGetValue(id ?? "", out definition); } internal static bool TryGetBarracks(string id, out RTSBarracksDefinition definition) { return Barracks.TryGetValue(id ?? "", out definition); } internal static bool TryGetBarracksByPrefab(string prefabName, out RTSBarracksDefinition definition) { return BarracksByPrefab.TryGetValue(RTSUtil.CleanPrefabName(prefabName), out definition); } internal static RTSBarracksDefinition ResolveProfile(RTSBarracksDefinition host, string selectedProfileId) { if (host == null) { return null; } if (host.SelectableProfiles.Count == 0) { return host; } if (string.IsNullOrWhiteSpace(selectedProfileId)) { return null; } if (!host.SelectableProfiles.Any((string x) => string.Equals(x, selectedProfileId, StringComparison.OrdinalIgnoreCase))) { return null; } RTSBarracksDefinition definition; return TryGetBarracks(selectedProfileId, out definition) ? definition : null; } internal static List<RTSBarracksDefinition> GetSelectableProfiles(RTSBarracksDefinition host) { List<RTSBarracksDefinition> list = new List<RTSBarracksDefinition>(); if (host == null) { return list; } foreach (string selectableProfile in host.SelectableProfiles) { if (TryGetBarracks(selectableProfile, out RTSBarracksDefinition definition) && definition != null) { list.Add(definition); } } return list; } internal static List<RTSUnitDefinition> GetUnitsFor(RTSBarracksDefinition barracks) { List<RTSUnitDefinition> list = new List<RTSUnitDefinition>(); if (barracks == null) { return list; } foreach (string unitId in barracks.UnitIds) { if (TryGetUnit(unitId, out RTSUnitDefinition definition)) { list.Add(definition); } } return list; } private static RTSUnitDefinition ParseUnit(string id, Dictionary<string, string> v) { if (string.IsNullOrWhiteSpace(id)) { return null; } string a = Get(v, "Mode", "ReadyPrefab"); RTSUnitMode mode = (string.Equals(a, "PlayerCloneRecruit", StringComparison.OrdinalIgnoreCase) ? RTSUnitMode.PlayerCloneRecruit : (string.Equals(a, "HumanoidRecruit", StringComparison.OrdinalIgnoreCase) ? RTSUnitMode.HumanoidRecruit : RTSUnitMode.ReadyPrefab)); RTSUnitDefinition rTSUnitDefinition = new RTSUnitDefinition { Id = id, Enabled = GetBool(v, "Enabled", fallback: true), Mode = mode, Prefab = Get(v, "Prefab", ""), DisplayName = Get(v, "DisplayName", id), DisplayNameEnglish = Get(v, "DisplayNameEnglish", BuiltInUnitEnglishName(id, Get(v, "DisplayName", id))), CommandCost = Mathf.Max(1, GetInt(v, "CommandCost", 1)), RecruitTime = Mathf.Max(0f, GetFloat(v, "RecruitTime", 30f)), RequireArmoryLoadout = GetBool(v, "RequireArmoryLoadout", fallback: true), DropEquipmentOnDeath = GetBool(v, "DropEquipmentOnDeath", fallback: true), CustomizeAppearance = GetBool(v, "CustomizeAppearance", fallback: true), AmmoItem = Get(v, "AmmoItem", ""), AmmoCapacity = Mathf.Max(0, GetInt(v, "AmmoCapacity", 0)), AmmoPerAttack = Mathf.Max(0, GetInt(v, "AmmoPerAttack", 1)), PortraitZoom = Mathf.Clamp(GetFloat(v, "PortraitZoom", 1f), 0.25f, 4f), PortraitYOffset = GetFloat(v, "PortraitYOffset", 0f), PortraitYaw = GetFloat(v, "PortraitYaw", 0f) }; rTSUnitDefinition.RecruitCosts.AddRange(ParseCosts(Get(v, "RecruitCosts", ""))); rTSUnitDefinition.Loadout.AddRange(ParseCosts(Get(v, "Loadout", ""))); foreach (string item in SplitList(Get(v, "Names", ""))) { if (!rTSUnitDefinition.RecruitNames.Contains<string>(item, StringComparer.OrdinalIgnoreCase)) { rTSUnitDefinition.RecruitNames.Add(item); } } foreach (string item2 in SplitList(Get(v, "HairOptions", ""))) { if (!rTSUnitDefinition.HairOptions.Contains<string>(item2, StringComparer.OrdinalIgnoreCase)) { rTSUnitDefinition.HairOptions.Add(item2); } } foreach (string item3 in SplitList(Get(v, "BeardOptions", ""))) { if (!rTSUnitDefinition.BeardOptions.Contains<string>(item3, StringComparer.OrdinalIgnoreCase)) { rTSUnitDefinition.BeardOptions.Add(item3); } } if (string.IsNullOrWhiteSpace(rTSUnitDefinition.AmmoItem) || rTSUnitDefinition.AmmoCapacity <= 0) { rTSUnitDefinition.AmmoItem = ""; rTSUnitDefinition.AmmoCapacity = 0; rTSUnitDefinition.AmmoPerAttack = 0; } return rTSUnitDefinition; } private static RTSBarracksDefinition ParseBarracks(string id, Dictionary<string, string> v) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(id)) { return null; } RTSBarracksDefinition rTSBarracksDefinition = new RTSBarracksDefinition { Id = id, Enabled = GetBool(v, "Enabled", fallback: true), Prefab = Get(v, "Prefab", ""), ProfileOnly = GetBool(v, "ProfileOnly", fallback: false), DisplayName = Get(v, "DisplayName", id), DisplayNameEnglish = Get(v, "DisplayNameEnglish", BuiltInBarracksEnglishName(id, Get(v, "DisplayName", id))), AllowRename = GetBool(v, "AllowRename", fallback: true), AllowProfileChange = GetBool(v, "AllowProfileChange", fallback: false), LocalCommandLimit = Mathf.Max(1, GetInt(v, "LocalCommandLimit", 10)), QueueLimit = Mathf.Max(1, GetInt(v, "QueueLimit", 3)), MaxPerSettlement = Mathf.Max(0, GetInt(v, "MaxPerSettlement", 0)), SpawnOffset = ParseVector3(Get(v, "SpawnOffset", "0,0,3"), new Vector3(0f, 0f, 3f)) }; rTSBarracksDefinition.BuildCosts.AddRange(ParseCosts(Get(v, "BuildCosts", ""))); foreach (string item in SplitList(Get(v, "Units", ""))) { if (!rTSBarracksDefinition.UnitIds.Contains<string>(item, StringComparer.OrdinalIgnoreCase)) { rTSBarracksDefinition.UnitIds.Add(item); } } foreach (string item2 in SplitList(Get(v, "SelectableProfiles", ""))) { if (!rTSBarracksDefinition.SelectableProfiles.Contains<string>(item2, StringComparer.OrdinalIgnoreCase)) { rTSBarracksDefinition.SelectableProfiles.Add(item2); } } if (rTSBarracksDefinition.ProfileOnly) { rTSBarracksDefinition.Prefab = ""; } return rTSBarracksDefinition; } private static string BuiltInUnitEnglishName(string id, string fallback) { return (id ?? "") switch { "GeneralHuman" => "Human Settler", "CloneTrooper" => "Clone Trooper", "EwokWarrior" => "Ewok Warrior", "HumanGuard" => "Equipable Guard", _ => fallback, }; } private static string BuiltInBarracksEnglishName(string id, string fallback) { return (id ?? "") switch { "GeneralHuman" => "General Barracks", "CloneBarracks" => "Republic Barracks", "EwokVillage" => "Ewok Village", "ProfileHumans" => "Human Profile", "ProfileRepublic" => "Republic Profile", "ProfileEndor" => "Endor Profile", "GenericHost" => "Configurable Barracks", _ => fallback, }; } internal static List<RTSCost> ParseCostList(string value) { return ParseCosts(value).ToList(); } private static Dictionary<string, Dictionary<string, string>> ParseIniText(string text) { Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); string text2 = ""; string text3 = (text ?? "").Replace("\r\n", "\n").Replace("\r", "\n"); string[] array = text3.Split(new char[1] { '\n' }); foreach (string text4 in array) { string text5 = text4.Trim(); if (text5.Length == 0 || text5.StartsWith("#") || text5.StartsWith(";")) { continue; } if (text5.StartsWith("[") && text5.EndsWith("]")) { text2 = text5.Substring(1, text5.Length - 2).Trim(); if (!dictionary.ContainsKey(text2)) { dictionary[text2] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); } } else if (!string.IsNullOrWhiteSpace(text2)) { int num = text5.IndexOf('='); if (num > 0) { string key = text5.Substring(0, num).Trim(); string value = text5.Substring(num + 1).Trim(); dictionary[text2][key] = value; } } } return dictionary; } private static IEnumerable<RTSCost> ParseCosts(string value) { foreach (string token in SplitList(value)) { int colon = token.LastIndexOf(':'); if (colon > 0) { string prefab = token.Substring(0, colon).Trim(); if (int.TryParse(token.Substring(colon + 1).Trim(), out var amount) && amount > 0) { yield return new RTSCost { Prefab = prefab, Amount = amount }; } } } } private static IEnumerable<string> SplitList(string value) { return from x in (value ?? "").Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) select x.Trim() into x where x.Length > 0 select x; } private static string Get(Dictionary<string, string> v, string key, string fallback) { string value; return v.TryGetValue(key, out value) ? value.Trim() : fallback; } private static int GetInt(Dictionary<string, string> v, string key, int fallback) { int result; return int.TryParse(Get(v, key, ""), NumberStyles.Integer, CultureInfo.InvariantCulture, out result) ? result : fallback; } private static float GetFloat(Dictionary<string, string> v, string key, float fallback) { float result; return float.TryParse(Get(v, key, ""), NumberStyles.Float, CultureInfo.InvariantCulture, out result) ? result : fallback; } private static bool GetBool(Dictionary<string, string> v, string key, bool fallback) { string text = Get(v, key, fallback ? "true" : "false"); if (bool.TryParse(text, out var result)) { return result; } if (int.TryParse(text, out var result2)) { return result2 != 0; } return fallback; } private static Vector3 ParseVector3(string raw, Vector3 fallback) { //IL_002b: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_008b: 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) string[] array = (raw ?? "").Split(new char[1] { ',' }); if (array.Length != 3) { return fallback; } if (!float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { return fallback; } return new Vector3(result, result2, result3); } } internal static class RTSUtil { private static bool _languageCached; private static bool _cachedSpanish; private static float _nextLanguageRefresh; internal static long UtcTicks => DateTime.UtcNow.Ticks; internal static string CleanPrefabName(string value) { if (string.IsNullOrWhiteSpace(value)) { return ""; } string text = value.Trim(); if (text.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - "(Clone)".Length).Trim(); } return text; } internal static string PrefabName(GameObject go) { if ((Object)(object)go == (Object)null) { return ""; } try { return CleanPrefabName(Utils.GetPrefabName(go)); } catch { return CleanPrefabName(((Object)go).name); } } internal static GameObject ResolvePrefab(string prefabName) { string clean = CleanPrefabName(prefabName); if (clean.Length == 0) { return null; } try { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(clean); if ((Object)(object)prefab != (Object)null) { return prefab; } } } catch { } try { if ((Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(clean); if ((Object)(object)itemPrefab != (Object)null) { return itemPrefab; } } } catch { } try { return ((IEnumerable<GameObject>)Resources.FindObjectsOfTypeAll<GameObject>()).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => (Object)(object)x != (Object)null && string.Equals(CleanPrefabName(((Object)x).name), clean, StringComparison.OrdinalIgnoreCase))); } catch { return null; } } internal static string ResolveSharedItemName(string itemPrefab) { GameObject val = ResolvePrefab(itemPrefab); try { return ((val == null) ? null : val.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_name) ?? ""; } catch { return ""; } } internal static int CountItem(Player player, string itemPrefab) { if ((Object)(object)player == (Object)null) { return 0; } string text = ResolveSharedItemName(itemPrefab); if (string.IsNullOrWhiteSpace(text)) { return 0; } try { Inventory inventory = ((Humanoid)player).GetInventory(); return (inventory != null) ? inventory.CountItems(text, -1, true) : 0; } catch { return 0; } } internal static bool HasCosts(Player player, IEnumerable<RTSCost> costs, out string missing) { missing = ""; if ((Object)(object)player == (Object)null) { return false; } foreach (RTSCost item in costs ?? Enumerable.Empty<RTSCost>()) { int num = CountItem(player, item.Prefab); if (num >= item.Amount) { continue; } missing = item.Prefab + " " + num + "/" + item.Amount; return false; } return true; } internal static bool RemoveCosts(Player player, IEnumerable<RTSCost> costs) { if ((Object)(object)player == (Object)null) { return false; } List<RTSCost> list = (costs ?? Enumerable.Empty<RTSCost>()).ToList(); if (!HasCosts(player, list, out string _)) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } foreach (RTSCost item in list) { string text = ResolveSharedItemName(item.Prefab); if (string.IsNullOrWhiteSpace(text)) { return false; } try { inventory.RemoveItem(text, item.Amount, -1, true); } catch { return false; } } try { inventory.Changed(false, false); } catch { } return true; } internal static bool RemoveItem(Player player, string itemPrefab, int amount) { if ((Object)(object)player == (Object)null || amount <= 0) { return false; } string text = ResolveSharedItemName(itemPrefab); if (string.IsNullOrWhiteSpace(text)) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } try { if (inventory.CountItems(text, -1, true) < amount) { return false; } inventory.RemoveItem(text, amount, -1, true); inventory.Changed(false, false); return true; } catch { return false; } } internal static Player FindOnlinePlayer(long playerId) { try { return ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerID() == playerId)); } catch { return null; } } internal static void Message(Player player, string text, MessageType type = (MessageType)2) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || string.IsNullOrWhiteSpace(text)) { return; } try { ((Character)player).Message(type, text, 0, (Sprite)null, false); } catch { } } internal static bool IsSpanish() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (_languageCached && realtimeSinceStartup < _nextLanguageRefresh) { return _cachedSpanish; } try { Localization instance = Localization.instance; string text = ((instance != null) ? instance.GetSelectedLanguage() : null) ?? ""; _cachedSpanish = text.IndexOf("span", StringComparison.OrdinalIgnoreCase) >= 0; } catch { _cachedSpanish = false; } _languageCached = true; _nextLanguageRefresh = realtimeSinceStartup + 2f; return _cachedSpanish; } internal static string T(string spanish, string english) { return IsSpanish() ? spanish : english; } internal static string SanitizeName(string value, int max = 40) { string input = (value ?? "").Trim(); input = Regex.Replace(input, "<[^>]*>", ""); input = input.Replace("<", "").Replace(">", "").Replace("\r", " ") .Replace("\n", " "); while (input.Contains(" ")) { input = input.Replace(" ", " "); } if (input.Length > max) { input = input.Substring(0, max); } return input.Trim(); } internal static string FormatSeconds(double seconds) { if (seconds < 0.0) { seconds = 0.0; } TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); if (timeSpan.TotalHours >= 1.0) { return $"{(int)timeSpan.TotalHours:00}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } return $"{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } internal static void SetTamed(Character character, bool value) { if ((Object)(object)character == (Object)null) { return; } try { MethodInfo methodInfo = AccessTools.Method(((object)character).GetType(), "SetTamed", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(character, new object[1] { value }); return; } } catch { } try { AccessTools.Field(((object)character).GetType(), "m_tamed")?.SetValue(character, value); } catch { } } internal static void SetTamedFlag(Character character, bool value) { if ((Object)(object)character == (Object)null) { return; } try { (AccessTools.Field(typeof(Character), "m_tamed") ?? AccessTools.Field(((object)character).GetType(), "m_tamed"))?.SetValue(character, value); } catch { } try { ZNetView component = ((Component)character).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } if (!component.IsOwner()) { component.ClaimOwnership(); } if (component.IsOwner()) { ZDO zDO = component.GetZDO(); if (zDO != null) { zDO.Set(ZDOVars.s_tamed, value); } } } catch { } } internal static void SetFriendlyFaction(Character character) { if ((Object)(object)character == (Object)null) { return; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "m_faction") ?? AccessTools.Field(((object)character).GetType(), "m_faction"); if (fieldInfo != null && fieldInfo.FieldType.IsEnum) { fieldInfo.SetValue(character, Enum.ToObject(fieldInfo.FieldType, 0)); } } catch { } } internal static Character FindCharacterArg(object[] args) { if (args == null) { return null; } foreach (object obj in args) { Character val = (Character)((obj is Character) ? obj : null); if (val != null) { return val; } GameObject val2 = (GameObject)((obj is GameObject) ? obj : null); if (val2 != null) { Character component = val2.GetComponent<Character>(); if ((Object)(object)component != (Object)null) { return component; } } } return null; } internal static long GetPieceCreator(Piece piece) { if ((Object)(object)piece == (Object)null) { return 0L; } try { MethodInfo methodInfo = AccessTools.Method(((object)piece).GetType(), "GetCreator", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(piece, null); if (obj != null) { return Convert.ToInt64(obj); } } } catch { } try { object obj3 = AccessTools.Field(((object)piece).GetType(), "m_creator")?.GetValue(piece); if (obj3 != null) { return Convert.ToInt64(obj3); } } catch { } try { ZNetView component = ((Component)piece).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { return component.GetZDO().GetLong("creator", 0L); } } catch { } return 0L; } internal static void SetMonsterAiFollow(GameObject mob, GameObject target) { if ((Object)(object)mob == (Object)null) { return; } MonsterAI component = mob.GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null) { return; } try { AccessTools.Method(((object)component).GetType(), "SetFollowTarget", new Type[1] { typeof(GameObject) }, (Type[])null)?.Invoke(component, new object[1] { target }); } catch { } } internal static void SetMonsterAiPatrol(GameObject mob, Vector3 point) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mob == (Object)null) { return; } MonsterAI component = mob.GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null) { return; } try { AccessTools.Method(((object)component).GetType(), "SetPatrolPoint", new Type[1] { typeof(Vector3) }, (Type[])null)?.Invoke(component, new object[1] { point }); } catch { } } internal static void ResetMonsterAiPatrol(GameObject mob) { if ((Object)(object)mob == (Object)null) { return; } MonsterAI component = mob.GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null) { return; } try { AccessTools.Method(((object)component).GetType(), "ResetPatrolPoint", Type.EmptyTypes, (Type[])null)?.Invoke(component, null); } catch { } } internal static void ClearMonsterAiCombat(GameObject mob) { if (!((Object)(object)mob == (Object)null)) { ClearMonsterAiCombat(mob.GetComponent<MonsterAI>()); } } internal static void ClearMonsterAiCombat(MonsterAI ai) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ai == (Object)null) { return; } try { FindAiField(ai, "m_targetCreature")?.SetValue(ai, null); } catch { } try { FindAiField(ai, "m_targetStatic")?.SetValue(ai, null); } catch { } try { FindAiField(ai, "m_lastKnownTargetPos")?.SetValue(ai, ((Component)ai).transform.position); } catch { } try { FindAiField(ai, "m_beenAtLastPos")?.SetValue(ai, true); } catch { } try { FindAiField(ai, "m_timeSinceAttacking")?.SetValue(ai, 0f); } catch { } try { FindAiField(ai, "m_timeSinceSensedTargetCreature")?.SetValue(ai, 999f); } catch { } try { FindAiField(ai, "m_updateTargetTimer")?.SetValue(ai, 0.75f); } catch { } try { (AccessTools.Method(((object)ai).GetType(), "SetTargetInfo", new Type[1] { typeof(ZDOID) }, (Type[])null) ?? AccessTools.Method(typeof(BaseAI), "SetTargetInfo", new Type[1] { typeof(ZDOID) }, (Type[])null))?.Invoke(ai, new object[1] { ZDOID.None }); } catch { } try { (AccessTools.Method(((object)ai).GetType(), "SetAlerted", new Type[1] { typeof(bool) }, (Type[])null) ?? AccessTools.Method(typeof(BaseAI), "SetAlerted", new Type[1] { typeof(bool) }, (Type[])null))?.Invoke(ai, new object[1] { false }); } catch { } } internal static bool TryGetMonsterAiCombatTarget(MonsterAI ai, out Vector3 point, out bool isStatic) { //IL_0002: 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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; isStatic = false; if ((Object)(object)ai == (Object)null) { return false; } try { object? obj = FindAiField(ai, "m_targetCreature")?.GetValue(ai); Character val = (Character)((obj is Character) ? obj : null); if ((Object)(object)val != (Object)null) { point = ((Component)val).transform.position; return true; } } catch { } try { object? obj3 = FindAiField(ai, "m_targetStatic")?.GetValue(ai); StaticTarget val2 = (StaticTarget)((obj3 is StaticTarget) ? obj3 : null); if ((Object)(object)val2 != (Object)null) { point = val2.GetCenter(); isStatic = true; return true; } } catch { } return false; } internal static bool SetMonsterAiStaticTarget(MonsterAI ai, StaticTarget target) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ai == (Object)null || (Object)(object)target == (Object)null) { return false; } try { FindAiField(ai, "m_targetCreature")?.SetValue(ai, null); FindAiField(ai, "m_targetStatic")?.SetValue(ai, target); FindAiField(ai, "m_lastKnownTargetPos")?.SetValue(ai, target.GetCenter()); FindAiField(ai, "m_beenAtLastPos")?.SetValue(ai, false); FindAiField(ai, "m_timeSinceAttacking")?.SetValue(ai, 0f); (AccessTools.Method(((object)ai).GetType(), "SetAlerted", new Type[1] { typeof(bool) }, (Type[])null) ?? AccessTools.Method(typeof(BaseAI), "SetAlerted", new Type[1] { typeof(bool) }, (Type[])null))?.Invoke(ai, new object[1] { true }); return true; } catch { return false; } } private static FieldInfo FindAiField(MonsterAI ai, string name) { if ((Object)(object)ai == (Object)null || string.IsNullOrWhiteSpace(name)) { return null; } Type type = ((object)ai).GetType(); while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } return null; } } internal static class RTSPieceCostOverrides { private static readonly HashSet<string> LastAppliedSignature = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static void ClearCache() { LastAppliedSignature.Clear(); } internal static void ApplyAll() { if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } foreach (RTSBarracksDefinition allPhysicalBarrack in RTSDefinitionRegistry.AllPhysicalBarracks) { if (allPhysicalBarrack == null || allPhysicalBarrack.BuildCosts.Count == 0) { continue; } GameObject val = RTSUtil.ResolvePrefab(allPhysicalBarrack.Prefab); Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null); if (!((Object)(object)val2 == (Object)null)) { string item = allPhysicalBarrack.Id + "=" + string.Join(",", allPhysicalBarrack.BuildCosts.Select((RTSCost c) => c.Prefab + ":" + c.Amount)); if (!LastAppliedSignature.Contains(item) && ApplyCostsToPiece(val2, allPhysicalBarrack.BuildCosts)) { LastAppliedSignature.Add(item); } } } } internal static bool ApplyCostsToPiece(Piece piece, IList<RTSCost> costs) { if ((Object)(object)piece == (Object)null || costs == null || costs.Count == 0) { return false; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(Piece), "m_resources"); Type type = (fieldInfo?.FieldType)?.GetElementType(); if (fieldInfo == null || type == null) { return false; } Array array = Array.CreateInstance(type, costs.Count); for (int i = 0; i < costs.Count; i++) { RTSCost rTSCost = costs[i]; GameObject val = RTSUtil.ResolvePrefab(rTSCost.Prefab); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { return false; } object obj = Activator.CreateInstance(type); AccessTools.Field(type, "m_resItem")?.SetValue(obj, val2); AccessTools.Field(type, "m_amount")?.SetValue(obj, Mathf.Max(1, rTSCost.Amount)); AccessTools.Field(type, "m_amountPerLevel")?.SetValue(obj, 0); AccessTools.Field(type, "m_recover")?.SetValue(obj, true); array.SetValue(obj, i); } fieldInfo.SetValue(piece, array); return true; } catch (Exception ex) { sunnfjordheimmodularPlugin.Debug("Could not apply piece costs to " + ((Object)piece).name + ": " + ex.Message); return false; } } } internal static class RTSTameGuildWarsCompat { private static bool _resolved; private static float _nextResolveAttempt; private static Type _tamedGuildMobType; private static Type _stanceType; private static MethodInfo _getPlayerGuildName; private static MethodInfo _isAlly; private static MethodInfo _tryClaim; private static MethodInfo _setStance; private static PropertyInfo _skipDecay; internal static bool Available => Resolve(); private static bool Resolve() { if (_resolved && _tamedGuildMobType != null) { return true; } if (Time.realtimeSinceStartup < _nextResolveAttempt) { return false; } _nextResolveAttempt = Time.realtimeSinceStartup + 2f; try { Assembly assembly = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly2 in assemblies) { if (!(assembly2 == null)) { Type type = null; try { type = assembly2.GetType("TameGuildWars.TamedGuildMob", throwOnError: false); } catch { } if (type != null) { assembly = assembly2; _tamedGuildMobType = type; break; } } } if (assembly == null || _tamedGuildMobType == null) { return false; } _stanceType = assembly.GetType("TameGuildWars.GuildMobStance", throwOnError: false); Type type2 = assembly.GetType("TameGuildWars.GuildUtils", throwOnError: false); if (_stanceType == null) { return false; } _getPlayerGuildName = type2?.GetMethod("GetPlayerGuildName", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Player) }, null); _isAlly = type2?.GetMethod("IsAlly", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(string), typeof(string) }, null); _tryClaim = _tamedGuildMobType.GetMethod("TryClaim", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(Player), typeof(string) }, null); _setStance = _tamedGuildMobType.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "SetStance" && m.GetParameters().Length >= 1 && m.GetParameters()[0].ParameterType == _stanceType); _skipDecay = _tamedGuildMobType.GetProperty("SkipDecay", BindingFlags.Instance | BindingFlags.Public); _resolved = true; sunnfjordheimmodularPlugin.Debug("TameGuildWars integration detected and ready."); return true; } catch (Exception ex) { sunnfjordheimmodularPlugin.Debug("TGW reflection not ready yet: " + ex.Message); _resolved = false; return false; } } internal static string GetPlayerGuildName(Player player) { if ((Object)(object)player == (Object)null || !Resolve() || _getPlayerGuildName == null) { return ""; } try { return (_getPlayerGuildName.Invoke(null, new object[1] { player }) as string) ?? ""; } catch { return ""; } } internal static bool ArePlayersGuildFriendly(Player first, Player second) { if ((Object)(object)first == (Object)null || (Object)(object)second == (Object)null) { return false; } string playerGuildName = GetPlayerGuildName(first); string playerGuildName2 = GetPlayerGuildName(second); if (string.IsNullOrWhiteSpace(playerGuildName) || string.IsNullOrWhiteSpace(playerGuildName2) || string.Equals(playerGuildName, "No Guild", StringComparison.OrdinalIgnoreCase) || string.Equals(playerGuildName2, "No Guild", StringComparison.OrdinalIgnoreCase) || string.Equals(playerGuildName, "Sin Guild", StringComparison.OrdinalIgnoreCase) || string.Equals(playerGuildName2, "Sin Guild", StringComparison.OrdinalIgnoreCase)) { return false; } if (string.Equals(playerGuildName, playerGuildName2, StringComparison.OrdinalIgnoreCase)) { return true; } if (_isAlly == null) { return false; } try { object obj = _isAlly.Invoke(null, new object[2] { playerGuildName, playerGuildName2 }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } internal static void Integrate(GameObject mob, Player recruiter) { if ((Object)(object)mob == (Object)null || (Object)(object)recruiter == (Object)null) { return; } ConfigEntry<sunnfjordheimmodularPlugin.Toggle> tgwIntegration = sunnfjordheimmodularPlugin.TgwIntegration; if (tgwIntegration == null || tgwIntegration.Value != sunnfjordheimmodularPlugin.Toggle.On || !Resolve() || _tamedGuildMobType == null) { return; } try { Component obj = mob.GetComponent(_tamedGuildMobType) ?? mob.AddComponent(_tamedGuildMobType); string playerGuildName = GetPlayerGuildName(recruiter); if (!string.IsNullOrWhiteSpace(playerGuildName) && !string.Equals(playerGuildName, "No Guild", StringComparison.OrdinalIgnoreCase) && _tryClaim != null) { _tryClaim.Invoke(obj, new object[2] { recruiter, playerGuildName }); } if (_skipDecay != null && _skipDecay.CanWrite) { ConfigEntry<sunnfjordheimmodularPlugin.Toggle> tgwSkipDecay = sunnfjordheimmodularPlugin.TgwSkipDecay; if (tgwSkipDecay != null && tgwSkipDecay.Value == sunnfjordheimmodularPlugin.Toggle.On) { _skipDecay.SetValue(obj, true, null); } } } catch (Exception ex) { sunnfjordheimmodularPlugin.Debug("TGW integration failed: " + ex.Message); } } internal static bool TrySetStance(GameObject mob, Player commander, string stanceName) { if (!((Object)(object)mob == (Object)null)) { ConfigEntry<sunnfjordheimmodularPlugin.Toggle> tgwIntegration = sunnfjordheimmodularPlugin.TgwIntegration; if (tgwIntegration != null && tgwIntegration.Value == sunnfjordheimmodularPlugin.Toggle.On) { if (!Resolve() || _tamedGuildMobType == null || _stanceType == null || _setStance == null) { return false; } try { Component component = mob.GetComponent(_tamedGuildMobType); if ((Object)(object)component == (Object)null) { return false; } object obj = Enum.Parse(_stanceType, stanceName, ignoreCase: true); ParameterInfo[] parameters = _setStance.GetParameters(); object[] array = new object[parameters.Length]; array[0] = obj; if (parameters.Length > 1) { array[1] = commander; } if (parameters.Length > 2) { array[2] = false; } object obj2 = _setStance.Invoke(component, array); bool flag = default(bool); int num; if (obj2 is bool) { flag = (bool)obj2; num = ((1 == 0) ? 1 : 0); } else { num = 1; } return (byte)((uint)num | (flag ? 1u : 0u)) != 0; } catch (Exception ex) { sunnfjordheimmodularPlugin.Debug("TGW SetStance " + stanceName + " failed: " + ex.Message); return false; } } } return false; } } internal static class RTSPortablePalsCompat { private const string StateKey = "Sunnfjordheim_RTS_State_v1"; private const string HarmonyId = "Azathoth.SunnfjordheimModularv1.PortablePals"; private const string TameGuildWarsHarmonyId = "WackyMole.TameGuildWars"; private static bool _patched; private static float _nextAttempt; internal static void Tick() { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown if (_patched || Time.unscaledTime < _nextAttempt) { return; } _nextAttempt = Time.unscaledTime + 2f; Type type = FindLoadedType("PortablePals.API"); if (type == null) { return; } try { Type typeFromHandle = typeof(Dictionary<string, string>); MethodInfo method = type.GetMethod("SaveDataToPalStone", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Character), typeFromHandle }, null); MethodInfo method2 = type.GetMethod("ReleaseCreature_PostAwake", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Character), typeFromHandle }, null); MethodInfo method3 = type.GetMethod("CanCapture", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Character), typeof(Player) }, null); if (method == null || method2 == null || method3 == null) { return; } MethodInfo method4 = type.GetMethod("AddZDOToSavedValues", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null); if (method4 != null) { string[] portableZdoKeys = RTSRecruitUnit.PortableZdoKeys; foreach (string text in portableZdoKeys) { method4.Invoke(null, new object[1] { text }); } } Harmony val = new Harmony("Azathoth.SunnfjordheimModularv1.PortablePals"); val.Patch((MethodBase)method, (HarmonyMethod)null, OrderedPatch("SaveDataPostfix", 0), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)method2, (HarmonyMethod)null, OrderedPatch("ReleaseDataPostfix", 0), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)method3, (HarmonyMethod)null, OrderedPatch("CanCapturePostfix", 0), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patched = true; sunnfjordheimmodularPlugin.Log.LogInfo((object)"[RTS Compat] Portable Pals detected: RTS owner, group, barracks and order state will be preserved."); } catch (Exception ex) { sunnfjordheimmodularPlugin.Log.LogWarning((object)("[RTS Compat] Portable Pals bridge is not ready yet: " + ex.Message)); } } private static HarmonyMethod OrderedPatch(string methodName, int priority) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(typeof(RTSPortablePalsCompat), methodName, (Type[])null); val.priority = priority; val.after = new string[1] { "WackyMole.TameGuildWars" }; return val; } private static Type FindLoadedType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly?.GetType(fullName, throwOnError: false); if (type != null) { return type; } } catch { } } return null; } public static void SaveDataPostfix(Character character, Dictionary<string, string> customData) { if (!sunnfjordheimmodularPlugin.IsEnabled || (Object)(object)character == (Object)null || customData == null) { return; } RTSRecruitUnit rTSRecruitUnit = ((Component)character).GetComponent<RTSRecruitUnit>(); if ((Object)(object)rTSRecruitUnit == (Object)null && RTSRecruitUnit.IsMarkedZdo(character)) { rTSRecruitUnit = ((Component)character).gameObject.AddComponent<RTSRecruitUnit>(); } if (!((Object)(object)rTSRecruitUnit == (Object)null)) { string value = rTSRecruitUnit.ExportPortableState(); if (!string.IsNullOrWhiteSpace(value)) { customData["Sunnfjordheim_RTS_State_v1"] = value; } } } public static void ReleaseDataPostfix(Character character, Dictionary<string, string> customData) { if (!sunnfjordheimmodularPlugin.IsEnabled || (Object)(object)character == (Object)null || customData == null) { return; } customData.TryGetValue("Sunnfjordheim_RTS_State_v1", out string value); RTSRecruitUnit rTSRecruitUnit = ((Component)character).GetComponent<RTSRecruitUnit>(); if ((Object)(object)rTSRecruitUnit == (Object)null && (!string.IsNullOrWhiteSpace(value) || RTSRecruitUnit.IsMarkedZdo(character))) { rTSRecruitUnit = ((Component)character).gameObject.AddComponent<RTSRecruitUnit>(); } if (!((Object)(object)rTSRecruitUnit == (Object)null)) { if (!string.IsNullOrWhiteSpace(value) && !rTSRecruitUnit.RestorePortableState(value)) { sunnfjordheimmodularPlugin.Log.LogWarning((object)"[RTS Compat] A Portable Pal contained invalid RTS state; it was not relinked."); return; } Player owner = RTSUtil.FindOnlinePlayer(rTSRecruitUnit.OwnerPlayerId); rTSRecruitUnit.PrepareAfterPortableRelease(owner); sunnfjordheimmodularPlugin.Log.LogInfo((object)("[RTS Compat] Portable Pal restored as RTS unit " + rTSRecruitUnit.UnitId + " (owner=" + rTSRecruitUnit.OwnerPlayerId + ", G" + rTSRecruitUnit.GroupNumber + ").")); } } public static void CanCapturePostfix(Character character, Player player, ref bool __result) { if (sunnfjordheimmodularPlugin.IsEnabled && !((Object)(object)character == (Object)null) && !((Object)(object)player == (Object)null)) { RTSRecruitUnit component = ((Component)character).GetComponent<RTSRecruitUnit>(); if (!((Object)(object)component == (Object)null) && component.OwnerPlayerId != 0L && component.OwnerPlayerId == player.GetPlayerID() && character.IsTamed()) { __result = true; } } } } internal static class RTSFriendlyIdentity { internal static bool AreFriendly(Character first, Character second) { if ((Object)(object)first == (Object)null || (Object)(object)second == (Object)null) { return false; } RTSRecruitUnit component = ((Component)first).GetComponent<RTSRecruitUnit>(); RTSRecruitUnit component2 = ((Component)second).GetComponent<RTSRecruitUnit>(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && component.OwnerPlayerId != 0L && component.OwnerPlayerId == component2.OwnerPlayerId) { return true; } if ((Object)(object)component != (Object)null) { Player val = (Player)(object)((second is Player) ? second : null); if (val != null && component.OwnerPlayerId == val.GetPlayerID()) { return true; } } if ((Object)(object)component2 != (Object)null) { Player val2 = (Player)(object)((first is Player) ? first : null); if (val2 != null && component2.OwnerPlayerId == val2.GetPlayerID()) { return true; } } return false; } } [HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[] { typeof(Character) })] internal static class RTSFriendlyIdentityInstancePatch { [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "WackyMole.TameGuildWars" })] private static void Postfix(BaseAI __instance, Character other, ref bool __result) { if (sunnfjordheimmodularPlugin.IsEnabled && __result && !((Object)(object)__instance == (Object)null)) { Character component = ((Component)__instance).GetComponent<Character>(); if (RTSFriendlyIdentity.AreFriendly(component, other)) { __result = false; } } } } [HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[] { typeof(Character), typeof(Character) })] internal static class RTSFriendlyIdentityStaticPatch { [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "WackyMole.TameGuildWars" })] private static void Postfix(Character a, Character b, ref bool __result) { if (sunnfjordheimmodularPlugin.IsEnabled && __result && RTSFriendlyIdentity.AreFriendly(a, b)) { __result = false; } } } internal static class RTSPortalFollowerTransport { internal sealed class Batch { internal Player Player; internal readonly List<UnitEntry> Units = new List<UnitEntry>(); internal Vector3 Destination; internal Quaternion Rotation; internal float StartedAt; } internal sealed class UnitEntry { internal RTSRecruitUnit Unit; internal ZDOID NetworkId; internal long OwnerId; } private static readonly List<Batch> Pending = new List<Batch>(); internal static Batch Capture(Player player) { //IL_00a4: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) if (!sunnfjordheimmodularPlugin.IsEnabled || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return null; } long playerID = player.GetPlayerID(); Batch batch = new Batch { Player = player, StartedAt = Time.unscaledTime }; RTSRecruitUnit[] array = RTSRecruitUnit.ActiveUnits.ToArray(); foreach (RTSRecruitUnit rTSRecruitUnit in array) { if (!((Object)(object)rTSRecruitUnit == (Object)null) && ((Component)rTSRecruitUnit).gameObject.activeInHierarchy && rTSRecruitUnit.OwnerPlayerId == playerID && rTSRecruitUnit.Order == RTSOrderMode.FollowMe && !(Vector3.Distance(((Component)rTSRecruitUnit).transform.position, ((Component)player).transform.position) > 32f)) { batch.Units.Add(new UnitEntry { Unit = rTSRecruitUnit, NetworkId = rTSRecruitUnit.GetNetworkId(), OwnerId = playerID }); } } return (batch.Units.Count == 0) ? null : batch; } internal static void Queue(Batch batch, Player player) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (batch == null || (Object)(object)player == (Object)null || batch.Units.Count == 0) { return; } try { if (((Character)player).IsTeleporting()) { batch.Destination = player.m_teleportTargetPos; batch.Rotation = player.m_teleportTargetRot; batch.StartedAt = Time.unscaledTime; Pending.RemoveAll((Batch p) => p == null || (Object)(object)p.Player == (Object)(object)player); Pending.Add(batch); sunnfjordheimmodularPlugin.Debug("[RTS Portal] Waiting to move " + batch.Units.Count + " following units."); } } catch { } } internal static void Tick() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) if (!sunnfjordheimmodularPlugin.IsEnabled) { Pending.Clear(); return; } Vector3 val = default(Vector3); for (int num = Pending.Count - 1; num >= 0; num--) { Batch batch = Pending[num]; if (batch == null || (Object)(object)batch.Player == (Object)null || Time.unscaledTime - batch.StartedAt > 25f) { Pending.RemoveAt(num); continue; } try { if (((Character)batch.Player).IsTeleporting() || Vector3.Distance(((Component)batch.Player).transform.position, batch.Destination) > 18f) { continue; } goto IL_00d7; } catch { Pending.RemoveAt(num); } continue; IL_00d7: int num2 = 0; int count = batch.Units.Count; for (int i = 0; i < count; i++) { UnitEntry unitEntry = batch.Units[i]; if (unitEntry == null || unitEntry.OwnerId != batch.Player.GetPlayerID()) { continue; } float num3 = ((count <= 1) ? 0f : ((float)Math.PI * 2f * (float)i / (float)count)); float num4 = ((count <= 1) ? 2.2f : (3f + (float)(i / 8) * 1.5f)); ((Vector3)(ref val))..ctor(Mathf.Cos(num3) * num4, 0.25f, Mathf.Sin(num3) * num4); Vector3 destination = batch.Destination + batch.Rotation * val; RTSRecruitUnit unit = unitEntry.Unit; if ((Object)(object)unit != (Object)null && unit.Order == RTSOrderMode.FollowMe && unit.OwnerPlayerId == unitEntry.OwnerId) { if (unit.TeleportWithCommander(batch.Player, destination, batch.Rotation)) { num2++; } } else if (RTSRecruitUnit.TeleportUnloadedFollower(unitEntry.NetworkId, unitEntry.OwnerId, destination, batch.Rotation)) { num2++; } } Pending.RemoveAt(num); if (num2 > 0) { RTSUtil.Message(batch.Player, RTSUtil.T($"{num2} tropa(s) cruzaron el portal.", $"{num2} unit(s) crossed the portal."), (MessageType)1); sunnfjordheimmodularPlugin.Log.LogInfo((object)("[RTS Portal] Transported " + num2 + "/" + count + " following units.")); } } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] internal static class RTSPortalFollowerPatch { private static void Prefix(Player player, ref RTSPortalFollowerTransport.Batch __state) { __state = RTSPortalFollowerTransport.Capture(player); } private static void Postfix(Player player, RTSPortalFollowerTransport.Batch __state) { RTSPortalFollowerTransport.Queue(__state, player); } } internal enum RTSOrderMode { FollowMe, DefendCenter, Stay, ReturnHome, Patrol, MoveTo, AssaultArea, AttackTarget } internal enum RTSSettlementUpgradeKind { Military, Logistics } internal sealed class RTSCommandCenter : MonoBehaviour, Hoverable, Interactable, TextReceiver { internal static readonly HashSet<RTSCommandCenter> ActiveCenters = new HashSet<RTSCommandCenter>(); private const string KeySettlementId = "RTS_SettlementId"; private const string KeyCustomName = "RTS_CommandName"; private const string KeyOwnerId = "RTS_CommandOwner"; private const string KeyOwnerName = "RTS_CommandOwnerName"; private const string KeyGuildName = "RTS_CommandGuild"; private const string KeyAllowGuild = "RTS_CommandAllowGuild"; private const string KeyRegistrationOpen = "RTS_CommandRegistrationOpen"; private const string KeyManagers = "RTS_CommandManagers"; private const string KeyValid = "RTS_CommandValid"; private const string KeyMilitaryUsed = "RTS_CommandMilitaryUsed"; private const string KeyCreatedTicks = "RTS_CommandCreatedTicks"; private ZNetView _nview; private Piece _piece; private bool _renaming; private float _nextTick; internal string SettlementId { get { ZDO zdo = GetZdo(); return ((zdo != null) ? zdo.GetString("RTS_SettlementId", "") : null) ?? ""; } } internal long OwnerId { get { ZDO zdo = GetZdo(); return (zdo != null) ? zdo.GetLong("RTS_CommandOwner", 0L) : 0; } } internal string OwnerName { get { ZDO zdo = GetZdo(); return ((zdo != null) ? zdo.GetString("RTS_CommandOwnerName", "") : null) ?? ""; } } internal string GuildName { get { ZDO zdo = GetZdo(); return ((zdo != null) ? zdo.GetString("RTS_CommandGuild", "") : null) ?? ""; } } internal bool AllowGuild { get { ZDO zdo = GetZdo(); int result; if (zdo == null) { result = 0; } else { ConfigEntry<sunnfjordheimmodularPlugin.Toggle> defaultGuildManagement = sunnfjordheimmodularPlugin.DefaultGuildManagement; result = (zdo.GetBool("RTS_CommandAllowGuild", defaultGuildManagement != null && defaultGuildManagement.Value == sunnfjordheimmodularPlugin.Toggle.On) ? 1 : 0); } return (byte)result != 0; } } internal bool RegistrationOpen { get { ZDO zdo = GetZdo(); return zdo != null && zdo.GetBool("RTS_CommandRegistrationOpen", false); } } internal bool IsValidCenter { get { ZDO zdo = GetZdo(); return zdo == null || zdo.GetBool("RTS_CommandValid", true); } } internal float Radius => Mathf.Max(20f, sunnfjordheimmodularPlugin.CommandRadius?.Value ?? 200f); private string AffiliationKey { get { if (!string.IsNullOrWhiteSpace(GuildName)) { return "G:" + GuildName.Trim().ToLowerInvariant(); } return "P:" + OwnerId; } } private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _piece = ((Component)this).GetComponent<Piece>(); } private void Start() { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { EnsureIdentity(null); } } private void OnEnable() { ActiveCenters.Add(this); } private void OnDisable() { ActiveCenters.Remove(this); } private void OnDestroy() { ActiveCenters.Remove(this); } private void Update() { if (!sunnfjordheimmodularPlugin.IsEnabled || Time.time < _nextTick) { return; } _nextTick = Time.time + 2f; if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { EnsureIdentity(null); if (IsValidCenter) { ValidateDistanceRule(); } } } private ZDO GetZdo() { try { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO() : null; } catch { return null; } } private bool EnsureOwnership() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } try { if (!_nview.IsOwner()) { _nview.ClaimOwnership(); } return _nview.IsOwner(); } catch { return false; } } private void EnsureIdentity(Player fallbackOwner) { ZDO zdo = GetZdo(); if (zdo == null || !EnsureOwnership()) { return; } if (string.IsNullOrWhiteSpace(zdo.GetString("RTS_SettlementId", ""))) { zdo.Set("RTS_SettlementId", Guid.NewGuid().ToString("N")); } if (zdo.GetLong("RTS_CommandCreatedTicks", 0L) == 0) { zdo.Set("RTS_CommandCreatedTicks", RTSUtil.UtcTicks); } long num = zdo.GetLong("RTS_CommandOwner", 0L); if (num == 0) { num = RTSUtil.GetPieceCreator(_piece); if (num == 0L && (Object)(object)fallbackOwner != (Object)null) { num = fallbackOwner.GetPlayerID(); } if (num != 0) { zdo.Set("RTS_CommandOwner", num); Player val = RTSUtil.FindOnlinePlayer(num) ?? fallbackOwner; if ((Object)(object)val != (Object)null) { zdo.Set("RTS_CommandOwnerName", val.GetPlayerName() ?? ""); string playerGuildName = RTSTameGuildWarsCompat.GetPlayerGuildName(val); if (!string.IsNullOrWhiteSpace(playerGuildName) && !string.Equals(playerGuildName, "No Guild", StringComparison.OrdinalIgnoreCase)) { zdo.Set("RTS_CommandGuild", playerGuildName.Trim()); } } } } if (string.IsNullOrWhiteSpace(zdo.GetString("RTS_CommandGuild", "")) && num != 0) { Player val2 = RTSUtil.FindOnlinePlayer(num); if ((Object)(object)val2 != (Object)null) { if (string.IsNullOrWhiteSpace(zdo.GetString("RTS_CommandOwnerName", ""))) { zdo.Set("RTS_CommandOwnerName", val2.GetPlayerName() ?? ""); } string playerGuildName2 = RTSTameGuildWarsCompat.GetPlayerGuildName(val2); if (!string.IsNullOrWhiteSpace(playerGuildName2) && !string.Equals(playerGuildName2, "No Guild", StringComparison.OrdinalIgnoreCase)) { zdo.Set("RTS_CommandGuild", playerGuildName2.Trim()); } } } if (!zdo.GetBool("RTS_CommandDefaultsSet", false)) { ConfigEntry<sunnfjordheimmodularPlugin.Toggle> defaultGuildManagement = sunnfjordheimmodularPlugin.DefaultGuildManagement; zdo.Set("RTS_CommandAllowGuild", defaultGuildManagement != null && defaultGuildManagement.Value == sunnfjordheimmodularPlugin.Toggle.On); zdo.Set("RTS_CommandRegistrationOpen", false); zdo.Set("RTS_CommandValid", true); zdo.Set("RTS_CommandDefaultsSet", true); } } private void ValidateDistanceRule() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!IsNetworkCenter(this) || CanPlaceCommandCenterAt(((Component)this).transform.position, this, out RTSCommandCenter conflict, out float minimumDistance, out float actualDistance)) { return; } ZDO zdo = GetZdo(); long num = ((zdo != null) ? zdo.GetLong("RTS_CommandCreatedTicks", long.MaxValue) : long.MaxValue); long? obj; if (conflict == null) { obj = null; } else { ZDO zdo2 = conflict.GetZdo(); obj = ((zdo2 != null) ? new long?(zdo2.GetLong("RTS_CommandCreatedTicks", long.MaxValue)) : ((long?)null)); } long num2 = obj ?? long.MaxValue; if (num >= num2) { ZDO zdo3 = GetZdo(); if (zdo3 != null) { zdo3.Set("RTS_CommandValid", false); } Player player = RTSUtil.FindOnlinePlayer(OwnerId); RTSUtil.Message(player, RTSUtil.T($"Estandarte de Mando inválido: hay otro centro a {actualDistance:0} m. Distancia mínima: {minimumDistance:0} m.", $"Invalid Command Banner: another center is {actualDistance:0} m away. Minimum distance: {minimumDistance:0} m."), (MessageType)2); } } internal static bool CanPlaceCommandCenterAt(Vector3 position, RTSCommandCenter ignore, out RTSCommandCenter conflict, out float minimumDistance, out float actualDistance) { //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_008a: Unknown result type (might be due to invalid IL or missing references) minimumDistance = Mathf.Max(20f, sunnfjordheimmodularPlugin.MinimumCommandCenterDistance?.Value ?? 350f); actualDistance = float.MaxValue; conflict = null; float num = minimumDistance * minimumDistance; RTSCommandCenter[] array = ActiveCenters.ToArray(); foreach (RTSCommandCenter rTSCommandCenter in array) { if ((Object)(object)rTSCommandCenter == (Object)null || (Object)(object)rTSCommandCenter == (Object)(object)ignore || !IsNetworkCenter(rTSCommandCenter) || !rTSCommandCenter.IsValidCenter) { continue; } Vector3 val = ((Component)rTSCommandCenter).transform.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude >= num)) { float num2 = Mathf.Sqrt(sqrMagnitude); if ((Object)(object)conflict == (Object)null || num2 < actualDistance) { conflict = rTSCommandCenter; actualDistance = num2; } } } return (Object)(object)conflict == (Object)null; } private static bool IsNetworkCenter(RTSCommandCenter center) { if ((Object)(object)center == (Object)null) { return false; } try { return (Object)(object)center._nview != (Object)null && center._nview.IsValid() && center.GetZdo() != null; } catch { return false; } } internal bool CanManage(Player player) { if ((Object)(object)player == (Object)null || !IsValidCenter) { return false; } EnsureIdentity(player); long playerID = player.GetPlayerID(); if (playerID == OwnerId) { return true; } if (GetManagerIds().Contains(playerID)) { return true; } if (AllowGuild && !string.IsNullOrWhiteSpace(GuildName) && string.Equals(RTSTameGuildWarsCompat.GetPlayerGuildName(player)?.Trim(), GuildName.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } return false; } internal bool CanRegister(Player player) { if ((Object)(object)player == (Object)null || !RegistrationOpen || IsOwner(player)) { return false; } if (!string.IsNullOrWhiteSpace(GuildName)) { return string.Equals(RTSTameGuildWarsCompat.GetPlayerGuildName(player)?.Trim(), GuildName.Trim(), StringComparison.OrdinalIgnoreCase); } return true; } internal bool IsOwner(Player player) { return (Object)(object)player != (Object)null && player.GetPlayerID() == OwnerId; } internal HashSet<long> GetManagerIds() { HashSet<long> hashSet = new HashSet<long>(); ZDO zdo = GetZdo(); string text = ((zdo != null) ? zdo.GetString("RTS_CommandManagers", "") : null) ?? ""; string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { if (long.TryParse(text2.Trim(), out var result) && result != 0) { hashSet.Add(result); } } return hashSet; } internal List<string> GetManualManagerDisplayNames() { List<string> list = new List<string>(); foreach (long item in from x in GetManagerIds() orderby x select x) { Player val = RTSUtil.FindOnlinePlayer(item); if ((Object)(object)val != (Object)null) { string playerName = val.GetPlayerName(); list.Add(string.IsNullOrWhiteSpace(playerName) ? item.ToString() : playerName); } else { list.Add("ID " + item); } } return list; } internal List<string> GetOnlineGuildAccessNames() { List<string> list = new List<string>(); if (!AllowGuild || string.IsNullOrWhiteSpace(GuildName)) { return list; } try { foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && allPlayer.GetPlayerID() != OwnerId && string.Equals(RTSTameGuildWarsCompat.GetPlayerGuildName(allPlayer)?.Trim(), GuildName.Trim(), StringComparison.OrdinalIgnoreCase)) { string playerName = allPlayer.GetPlayerName(); if (!string.IsNullOrWhiteSpace(playerName)) { list.Add(playerName); } } } } catch { } return (from x in list.Distinct<string>(StringComparer.OrdinalIgnoreCase) orderby x select x).ToList(); } private void SaveManagers(IEnumerable<long> managers) { if (EnsureOwnership()) { string text = string.Join(",", from x in (managers ?? Enumerable.Empty<long>()).Where((long x) => x != 0).Distinct() select x.ToString()); ZDO zdo = GetZdo(); if (zdo != null) { zdo.Set("RTS_CommandManagers", text); } } } internal bool RegisterManager(Player player) { if (!CanRegister(player) || !EnsureOwnership()) { return false; } HashSet<long> managerIds = GetManagerIds(); managerIds.Add(player.GetPlayerID()); SaveManagers(managerIds); return true; } internal bool UnregisterManager(Player player) { if ((Object)(object)player == (Object)null || IsOwner(player) || !EnsureOwnership()) { return false; } HashSet<long> managerIds = GetManagerIds(); bool flag = managerIds.Remove(player.GetPlayerID()); if (flag) { SaveManagers(managerIds); } return flag; } internal void ClearManagers(Player owner) { if (IsOwner(owner) && EnsureOwnership()) { SaveManagers(Array.Empty<long>()); } } internal void ToggleGuildAccess(Player owner) { if (IsOwner(owner) && EnsureOwnership()) { ZDO zdo = GetZdo(); if (zdo != null) { zdo.Set("RTS_CommandAllowGuild", !AllowGuild); } } } internal void ToggleRegistration(Player owner) { if (IsOwner(owner) && EnsureOwnership()) { ZDO zdo = GetZdo(); if (zdo != null) { zdo.Set("RTS_CommandRegistrationOpen", !RegistrationOpen); } } } internal int GetMilitaryCapacity() { int num = Mathf.Max(1, sunnfjordheimmodularPlugin.BaseSettlementMilitaryCap?.Value ?? 30); int num2 = RTSSettlementUpgrade.ActiveUpgrades.Count((RTSSettlementUpgrade u) => (Object)(object)u != (Object)null && u.Kind == RTSSettlementUpgradeKind.Military && u.IsBoundTo(SettlementId)); return num + num2 * Mathf.Max(0, sunnfjordheimmodularPlugin.MilitaryBannerCommandBonus?.Value ?? 20); } internal int GetBarracksLimit() { int num = Mathf.Max(1, sunnfjordheimmodularPlugin.BaseSettlementBarracksLimit?.Value ?? 2); int num2 = RTSSettlementUpgrade.ActiveUpgrades.Count((RTSSettlementUpgrade u) => (Object)(object)u != (Object)null && u.Kind == RTSSettlementUpgradeKind.Logistics && u.IsBoundTo(SettlementId)); return num + num2 * Mathf.Max(0, sunnfjordheimmodularPlugin.LogisticsBannerBarracksBonus?.Value ?? 1); } internal int GetMilitaryUsed() { ZDO zdo = GetZdo(); return Mathf.Max(0, (zdo != null) ? zdo.GetInt("RTS_CommandMilitaryUsed", 0) : 0); } internal bool TryReserveMilitary(int amount) { if (amount <= 0 || !EnsureOwnership()) { return false; } int militaryUsed = GetMilitaryUsed(); if (militaryUsed + amount > GetMilitaryCapacity()) { return false; } ZDO zdo = GetZdo(); if (zdo != null) { zdo.Set("RTS_CommandMilitaryUsed", militaryUsed + amount); } return true; } internal void ReleaseMilitary(int amount) { if (amount > 0 && EnsureOwnership()) { ZDO zdo = GetZdo(); if (zdo != null) { zdo.Set("RTS_CommandMilitaryUsed", Mathf.Max(0, GetMilitaryUsed() - amount)); } } } internal void RecountLoadedMilitary(Player manager) { if (!CanManage(manager) || !EnsureOwnership()) { return; } string id = SettlementId; int num = RTSRecruitUnit.ActiveUnits.Where((RTSRecruitUnit u) => (Object)(object)u != (Object)null && string.Equals(u.SettlementId, id, StringComparison.Ordinal)).Sum((RTSRecruitUnit u) => Mathf.Max(1, u.CommandCost)); int num2 = RTSRecruitmentStation.ActiveStations.Where((RTSRecruitmentStation s) => (Object)(object)s != (Object)null && string.Equals(s.SettlementId, id, StringComparison.Ordinal)).Sum((RTSRecruitmentStation s) => s.GetQueueSnapshot().Sum((RTSQueueEntry q) => Mathf.Max(1, q.CommandCost))); ZDO zdo = GetZdo(); if (zdo != null) { zdo.Set("RTS_CommandMilitaryUsed", num + num2); } } internal int GetRegisteredBarracksCount() { string id = SettlementId; return RTSRecruitmentStation.ActiveStations.Count((RTSRecruitmentStation s) => (Object)(object)s != (Object)null && s.IsRegistered && string.Equals(s.SettlementId, id, StringComparison.Ordinal)); } internal int GetProfileCount(string profileId, RTSRecruitmentStation? except = null) { if (string.IsNullOrWhiteSpace(profileId)) { return 0; } string id = SettlementId; return RTSRecruitmentStation.ActiveStations.Count((RTSRecruitmentStation s) => (Object)(object)s != (Object)null && (Object)(object)s != (Object)(object)except && s.IsRegistered && string.Equals(s.SettlementId, id, StringComparison.Ordinal) && string.Equals(s.ActiveProfileId, profileId, StringComparison.OrdinalIgnoreCase)); } internal List<RTSRecruitUnit> GetUnits() { return RTSRecruitUnit.ActiveUnits.Where((RTSRecruitUnit u) => (Object)(object)u != (Object)null && string.Equals(u.SettlementId, SettlementId, StringComparison.Ordinal)).ToList(); } internal List<RTSRecruitmentStation> GetBarracks() { return RTSRecruitmentStation.ActiveStations.Where((RTSRecruitmentStation s) => (Object)(object)s != (Object)null && s.IsRegistered && string.Equals(s.SettlementId, SettlementId, StringComparison.Ordinal)).ToList(); } internal void IssueOrderToAll(Player commander, RTSOrderMode order) { if (!CanManage(commander)) { return; } foreach (RTSRecruitUnit unit in GetUnits()) { unit?.IssueOrder(commander, order, this); } } public string GetHoverName() { ZDO zdo = GetZdo(); string text = ((zdo != null) ? zdo.GetString("RTS_CommandName", "") : null) ?? ""; return string.IsNullOrWhiteSpace(text) ? RTSUtil.T("Estandarte de Mando", "Command Banner") : text; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { string text