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 HelpfullWards v0.6.0
HelpfullWards.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("HelpfullWards")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+983531e3e25bab94cbf35f92f43bde49abfdf158")] [assembly: AssemblyProduct("HelpfullWards")] [assembly: AssemblyTitle("HelpfullWards")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HelpfullWards { public static class DamagedPieceTracker { public static readonly HashSet<WearNTear> Damaged = new HashSet<WearNTear>(); public static void SeedFromAllInstances() { foreach (WearNTear allInstance in WearNTear.GetAllInstances()) { if ((Object)(object)allInstance != (Object)null && allInstance.GetHealthPercentage() < 0.999f) { Damaged.Add(allInstance); } } } } [HarmonyPatch(typeof(WearNTear), "RPC_HealthChanged")] internal static class WearNTearHealthChangedPatch { private static void Postfix(WearNTear __instance, float health) { if (health < __instance.m_health * 0.999f) { DamagedPieceTracker.Damaged.Add(__instance); } else { DamagedPieceTracker.Damaged.Remove(__instance); } } } [HarmonyPatch(typeof(WearNTear), "OnDestroy")] internal static class WearNTearDestroyPatch { private static void Prefix(WearNTear __instance) { DamagedPieceTracker.Damaged.Remove(__instance); } } public static class EffectFinder { private const string DefaultOutputDir = "/home/michel/Documents/http/public/hierarchies"; public static void Dump(string keyword, string fileName) { if ((Object)(object)ZNetScene.instance == (Object)null) { Plugin.Logger.LogWarning((object)"[EffectFinder] ZNetScene not ready, abort."); return; } string text = (Path.IsPathRooted(fileName) ? fileName : Path.Combine("/home/michel/Documents/http/public/hierarchies", fileName)); List<(GameObject, bool)> list = new List<(GameObject, bool)>(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if (Matches(prefab, keyword)) { list.Add((prefab, true)); } } foreach (GameObject nonNetViewPrefab in ZNetScene.instance.m_nonNetViewPrefabs) { if (Matches(nonNetViewPrefab, keyword)) { list.Add((nonNetViewPrefab, false)); } } list = list.OrderBy<(GameObject, bool), string>(((GameObject prefab, bool networked) m) => ((Object)m.prefab).name).ToList(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"# Prefabs matching \"{keyword}\" — {list.Count} hit(s)"); stringBuilder.AppendLine(); foreach (var item2 in list) { GameObject item = item2.Item1; string value = (item2.Item2 ? "[Net]" : "[NonNet]"); stringBuilder.Append(value).Append(' ').Append(((Object)item).name) .Append(' '); stringBuilder.AppendLine(SummarizeComponents(item)); DumpChildren(stringBuilder, item.transform, 1); stringBuilder.AppendLine(); } Directory.CreateDirectory(Path.GetDirectoryName(text)); File.WriteAllText(text, stringBuilder.ToString(), Encoding.UTF8); Plugin.Logger.LogInfo((object)$"[EffectFinder] Wrote {list.Count} prefab(s) to: {text}"); } private static bool Matches(GameObject? prefab, string keyword) { if ((Object)(object)prefab != (Object)null) { return ((Object)prefab).name.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static void DumpChildren(StringBuilder sb, Transform parent, int depth) { for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); sb.Append(new string(' ', depth * 2)); sb.Append("└ "); sb.Append(((Object)child).name); sb.Append(' '); sb.AppendLine(SummarizeComponents(((Component)child).gameObject)); DumpChildren(sb, child, depth + 1); } } private static string SummarizeComponents(GameObject go) { List<string> list = new List<string>(); AppendCount<ParticleSystem>(go, "ParticleSystem", list); AppendCount<Light>(go, "Light", list); AppendCount<AudioSource>(go, "AudioSource", list); AppendCount<ZSFX>(go, "ZSFX", list); AppendCount<TrailRenderer>(go, "TrailRenderer", list); AppendCount<LineRenderer>(go, "LineRenderer", list); AppendCount<MeshRenderer>(go, "MeshRenderer", list); AppendCount<SkinnedMeshRenderer>(go, "SkinnedMeshRenderer", list); if ((Object)(object)go.GetComponent<ZNetView>() != (Object)null) { list.Add("ZNetView"); } if ((Object)(object)go.GetComponent<Aoe>() != (Object)null) { list.Add("Aoe"); } if ((Object)(object)go.GetComponent<TimedDestruction>() != (Object)null) { list.Add("TimedDestruction"); } StatusEffect component = go.GetComponent<StatusEffect>(); if ((Object)(object)component != (Object)null) { list.Add("SE:" + ((object)component).GetType().Name); } if (list.Count != 0) { return "[" + string.Join(", ", list) + "]"; } return ""; } private static void AppendCount<T>(GameObject go, string label, List<string> parts) where T : Component { int num = go.GetComponents<T>().Length; if (num != 0) { parts.Add((num == 1) ? label : $"{label}×{num}"); } } } public class ElementalWardBehavior : WardBehavior { public enum Element { Fire, Frost, Poison, Lightning, Spirit } public Element DamageElement; private static HashSet<Faction>? _excluded; protected override float Interval => WardConfig.ElementalTickInterval.Value; private static HashSet<Faction> Excluded => _excluded ?? (_excluded = WardConfig.GetExcludedFactions()); protected override bool Tick() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown float damage = GetDamage(); List<Character> list = new List<Character>(); Character.GetCharactersInRange(((Component)this).transform.position, Radius, list); List<Character> list2 = new List<Character>(); foreach (Character item in list) { if (!((Object)(object)item == (Object)null) && !Excluded.Contains(item.m_faction) && !item.IsTamed()) { list2.Add(item); } } if (list2.Count == 0) { return false; } Character val = list2[Random.Range(0, list2.Count)]; HitData val2 = new HitData { m_attacker = ZDOID.None }; switch (DamageElement) { case Element.Fire: val2.m_damage.m_fire = damage; break; case Element.Frost: val2.m_damage.m_frost = damage; break; case Element.Poison: val2.m_damage.m_poison = damage; break; case Element.Lightning: val2.m_damage.m_lightning = damage; break; case Element.Spirit: val2.m_damage.m_spirit = damage; break; } val.Damage(val2); return true; } private float GetDamage() { return DamageElement switch { Element.Fire => WardConfig.FireDamage.Value, Element.Frost => WardConfig.FrostDamage.Value, Element.Poison => WardConfig.PoisonDamage.Value, Element.Lightning => WardConfig.LightningDamage.Value, _ => WardConfig.SpiritDamage.Value, }; } } public class HealFlashStatusEffect : StatusEffect { public const string Name = "HW_HealFlash"; private const string FxPrefabName = "vfx_Potion_health_medium"; private static HealFlashStatusEffect? _cached; private GameObject? _vfxInstance; public static int Hash => StringExtensionMethods.GetStableHashCode("HW_HealFlash"); public static void Register() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { Plugin.Logger.LogWarning((object)"[HealFlashSE] ObjectDB not ready"); return; } if ((Object)(object)instance.GetStatusEffect(Hash) != (Object)null) { Plugin.Logger.LogInfo((object)$"[HealFlashSE] Already registered (hash={Hash})"); return; } if ((Object)(object)_cached == (Object)null) { _cached = ScriptableObject.CreateInstance<HealFlashStatusEffect>(); ((Object)_cached).name = "HW_HealFlash"; ((StatusEffect)_cached).m_name = "$hw_heal_flash"; ((StatusEffect)_cached).m_ttl = 1f; ((StatusEffect)_cached).m_icon = null; Object.DontDestroyOnLoad((Object)(object)_cached); } instance.m_StatusEffects.Add((StatusEffect)(object)_cached); Plugin.Logger.LogInfo((object)("[HealFlashSE] Registered " + $"(hash={Hash}, ODB#{((Object)instance).GetInstanceID()}, " + $"list#{instance.m_StatusEffects.GetHashCode()}, count={instance.m_StatusEffects.Count})")); } public override void Setup(Character character) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) Plugin.Logger.LogInfo((object)("[HealFlashSE] Setup ENTER on " + (((character != null) ? ((Object)character).name : null) ?? "null") + " (type=" + ((object)this).GetType().Name + ")")); try { base.m_character = character; ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab("vfx_Potion_health_medium") : null); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogWarning((object)"[HealFlashSE] Prefab not found: vfx_Potion_health_medium"); return; } bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; try { _vfxInstance = Object.Instantiate<GameObject>(val, ((Component)character).transform); _vfxInstance.transform.localPosition = Vector3.zero; _vfxInstance.transform.localRotation = Quaternion.identity; _vfxInstance.SetActive(true); Plugin.Logger.LogInfo((object)("[HealFlashSE] Instantiated " + ((Object)_vfxInstance).name + " " + $"world={_vfxInstance.transform.position} " + $"active={_vfxInstance.activeInHierarchy}")); } finally { ZNetView.m_forceDisableInit = forceDisableInit; } } catch (Exception arg) { Plugin.Logger.LogError((object)$"[HealFlashSE] Setup exception: {arg}"); } } public override void Stop() { _vfxInstance = null; } } public class HealingWardBehavior : WardBehavior { protected override float Interval => WardConfig.HealInterval.Value; protected override string? TickSoundPrefab => "sfx_dverger_heal_finish"; protected override bool Tick() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) playFlash = false; bool result = false; List<Character> list = new List<Character>(); Character.GetCharactersInRange(((Component)this).transform.position, Radius, list); foreach (Character item in list) { if (!((Object)(object)item == (Object)null) && !item.IsMonsterFaction(Time.time) && !(item.GetHealth() >= item.GetMaxHealth())) { result = true; item.GetSEMan().RemoveAllStatusEffects(true); item.Heal(WardConfig.HealAmount.Value, true); HealFlashStatusEffect.Register(); item.GetSEMan().AddStatusEffect(HealFlashStatusEffect.Hash, true, 0, 0f); } } return result; } } public class HelpfulWardArea : MonoBehaviour, Hoverable, Interactable { public string m_name = ""; public float m_radius = 10f; public bool m_enabledByDefault = true; public GameObject? m_enabledEffect; public MeshRenderer? m_model; public CircleProjector? m_areaMarker; public EffectList m_flashEffect = new EffectList(); public EffectList m_activateEffect = new EffectList(); public EffectList m_deactivateEffect = new EffectList(); private ZNetView m_nview; private Piece m_piece; private bool m_flashAvailable = true; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if (m_nview.IsValid()) { m_piece = ((Component)this).GetComponent<Piece>(); WearNTear component = ((Component)this).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { component.m_onDamaged = (Action)Delegate.Combine(component.m_onDamaged, new Action(OnDamaged)); } if ((Object)(object)m_areaMarker != (Object)null) { ((Component)m_areaMarker).gameObject.SetActive(false); } ((MonoBehaviour)this).InvokeRepeating("UpdateStatus", 0f, 1f); m_nview.Register<long>("ToggleEnabled", (Action<long, long>)RPC_ToggleEnabled); m_nview.Register("FlashShield", (Action<long>)RPC_FlashShield); if (m_enabledByDefault && m_nview.IsOwner()) { m_nview.GetZDO().Set(ZDOVars.s_enabled, true); } } } public bool IsEnabled() { if (!m_nview.IsValid()) { return false; } return m_nview.GetZDO().GetBool(ZDOVars.s_enabled, false); } private void SetEnabled(bool enabled) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) m_nview.GetZDO().Set(ZDOVars.s_enabled, enabled); UpdateStatus(); if (enabled) { m_activateEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } else { m_deactivateEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } } private void UpdateStatus() { bool flag = IsEnabled(); if ((Object)(object)m_enabledEffect != (Object)null) { m_enabledEffect.SetActive(flag); } m_flashAvailable = true; if (!((Object)(object)m_model != (Object)null)) { return; } Material[] materials = ((Renderer)m_model).materials; foreach (Material val in materials) { if (flag) { val.EnableKeyword("_EMISSION"); } else { val.DisableKeyword("_EMISSION"); } } } public string GetHoverName() { return m_name; } public string GetHoverText() { if (!m_nview.IsValid() || (Object)(object)Player.m_localPlayer == (Object)null) { return ""; } ShowAreaMarker(); string text = (IsEnabled() ? "$piece_guardstone_active" : "$piece_guardstone_inactive"); string text2 = m_name + " ( " + text + " )"; if (m_piece.IsCreator()) { string text3 = (IsEnabled() ? "$piece_guardstone_deactivate" : "$piece_guardstone_activate"); text2 = text2 + "\n[<color=yellow><b>$KEY_Use</b></color>] " + text3; } return Localization.instance.Localize(text2); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } if (!m_piece.IsCreator()) { return false; } m_nview.InvokeRPC("ToggleEnabled", new object[1] { ((Player)human).GetPlayerID() }); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } private void RPC_ToggleEnabled(long uid, long playerID) { if (m_nview.IsOwner() && m_piece.GetCreator() == playerID) { SetEnabled(!IsEnabled()); } } private void RPC_FlashShield(long uid) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) m_flashEffect.Create(((Component)this).transform.position, Quaternion.identity, (Transform)null, 1f, -1); } public void ShowAreaMarker() { if (!((Object)(object)m_areaMarker == (Object)null)) { ((Component)m_areaMarker).gameObject.SetActive(true); ((MonoBehaviour)this).CancelInvoke("HideMarker"); ((MonoBehaviour)this).Invoke("HideMarker", 0.5f); } } private void HideMarker() { if ((Object)(object)m_areaMarker != (Object)null) { ((Component)m_areaMarker).gameObject.SetActive(false); } } private void OnDamaged() { if (IsEnabled() && m_flashAvailable) { m_flashAvailable = false; m_nview.InvokeRPC(ZNetView.Everybody, "FlashShield", Array.Empty<object>()); } } } [BepInPlugin("Mordel2Berde.HelpfullWards", "HelpfullWards", "0.6.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "Mordel2Berde.HelpfullWards"; public const string PluginName = "HelpfullWards"; public const string PluginVersion = "0.6.0"; internal static ManualLogSource Logger; private readonly Harmony _harmony = new Harmony("Mordel2Berde.HelpfullWards"); private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; WardConfig.Init(((BaseUnityPlugin)this).Config); TranslationLoader.Load(); PrefabManager.OnVanillaPrefabsAvailable += WardFactory.RegisterWards; PrefabManager.OnVanillaPrefabsAvailable += HealFlashStatusEffect.Register; _harmony.PatchAll(); } private void OnDestroy() { _harmony.UnpatchSelf(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyOtherDBPatch { [HarmonyPostfix] private static void Postfix() { HealFlashStatusEffect.Register(); } } public class RepairWardBehavior : WardBehavior { protected override float Interval => WardConfig.RepairInterval.Value; private void Start() { DamagedPieceTracker.SeedFromAllInstances(); } protected override bool Tick() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) playFlash = false; float num = Radius * Radius; Vector3 position = ((Component)this).transform.position; foreach (WearNTear item in DamagedPieceTracker.Damaged) { if ((Object)(object)item == (Object)null) { continue; } Vector3 val = ((Component)item).transform.position - position; if (((Vector3)(ref val)).sqrMagnitude > num) { continue; } ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { component.InvokeRPC(component.GetZDO().GetOwner(), "RPC_Repair", Array.Empty<object>()); Piece component2 = ((Component)item).GetComponent<Piece>(); if (component2 != null) { component2.m_placeEffect.Create(((Component)item).transform.position, ((Component)item).transform.rotation, (Transform)null, 1f, -1); } return true; } } return false; } } public static class TranslationLoader { private static readonly string TranslationsDir = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "Translations"); public static void Load() { if (!Directory.Exists(TranslationsDir)) { Directory.CreateDirectory(TranslationsDir); WriteDefaults(); } string[] files = Directory.GetFiles(TranslationsDir, "*.json"); foreach (string text in files) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); try { Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(text, Encoding.UTF8)); if (dictionary == null || dictionary.Count == 0) { continue; } CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); foreach (KeyValuePair<string, string> item in dictionary) { string key = item.Key; localization.AddTranslation(ref fileNameWithoutExtension, ref key, item.Value); } Plugin.Logger.LogInfo((object)$"[HelpfullWards] Translations loaded: {fileNameWithoutExtension} ({dictionary.Count} entries)"); } catch (Exception ex) { Plugin.Logger.LogError((object)("[HelpfullWards] Error reading " + text + ": " + ex.Message)); } } } private static void WriteDefaults() { Write("English", new Dictionary<string, string> { { "hw_ward_fire", "Fire Ward" }, { "hw_ward_fire_desc", "Deals fire damage periodically to enemies within range." }, { "hw_ward_frost", "Frost Ward" }, { "hw_ward_frost_desc", "Deals frost damage periodically to enemies within range." }, { "hw_ward_poison", "Poison Ward" }, { "hw_ward_poison_desc", "Deals poison damage periodically to enemies within range." }, { "hw_ward_lightning", "Lightning Ward" }, { "hw_ward_lightning_desc", "Deals lightning damage periodically to enemies within range." }, { "hw_ward_spirit", "Spirit Ward" }, { "hw_ward_spirit_desc", "Deals spirit damage periodically to enemies within range." }, { "hw_ward_repair", "Repair Ward" }, { "hw_ward_repair_desc", "Automatically repairs damaged constructions within range." }, { "hw_ward_healing", "Healing Ward" }, { "hw_ward_healing_desc", "Periodically heals players within range." } }); Write("French", new Dictionary<string, string> { { "hw_ward_fire", "Balise de feu" }, { "hw_ward_fire_desc", "Inflige des dégâts de feu périodiques aux ennemis dans son rayon." }, { "hw_ward_frost", "Balise de givre" }, { "hw_ward_frost_desc", "Inflige des dégâts de givre périodiques aux ennemis dans son rayon." }, { "hw_ward_poison", "Balise de poison" }, { "hw_ward_poison_desc", "Inflige des dégâts de poison périodiques aux ennemis dans son rayon." }, { "hw_ward_lightning", "Balise de foudre" }, { "hw_ward_lightning_desc", "Inflige des dégâts de foudre périodiques aux ennemis dans son rayon." }, { "hw_ward_spirit", "Balise spirituelle" }, { "hw_ward_spirit_desc", "Inflige des dégâts d'esprit périodiques aux ennemis dans son rayon." }, { "hw_ward_repair", "Balise de Réparation" }, { "hw_ward_repair_desc", "Répare automatiquement les constructions endommagées dans son rayon." }, { "hw_ward_healing", "Balise de Soin" }, { "hw_ward_healing_desc", "Soigne périodiquement les joueurs dans son rayon." } }); } private static void Write(string language, Dictionary<string, string> entries) { string text = Path.Combine(TranslationsDir, language + ".json"); if (!File.Exists(text)) { File.WriteAllText(text, JsonConvert.SerializeObject((object)entries, (Formatting)1), Encoding.UTF8); Plugin.Logger.LogInfo((object)("[HelpfullWards] Translation file created: " + text)); } } } public abstract class WardBehavior : MonoBehaviour { private const float MaxCharge = 1f; private ZNetView _nview; private HelpfulWardArea _wardArea; private Light? _wardLight; private float _baseIntensity; private float _charge = 1f; private float _rechargeDuration; public float Radius; protected bool playFlash = true; protected abstract float Interval { get; } protected virtual string? TickSoundPrefab => null; protected abstract bool Tick(); private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _wardArea = ((Component)this).GetComponent<HelpfulWardArea>(); _wardLight = ((Component)this).GetComponentInChildren<Light>(); _baseIntensity = (((Object)(object)_wardLight != (Object)null) ? _wardLight.intensity : 1f); _nview.Register<float>("HW_Discharge", (Action<long, float>)RPC_Discharge); } private void Update() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && _wardArea.IsEnabled() && !(_charge < 1f) && Tick()) { float num = Interval + (Random.Range(0f, 2f * Interval) - Interval) / 10f; _nview.InvokeRPC(ZNetView.Everybody, "HW_Discharge", new object[1] { num }); } } private void RPC_Discharge(long sender, float duration) { PlayTickEffect(); _charge = 0f; _rechargeDuration = Mathf.Max(0.01f, duration); if ((Object)(object)_wardLight != (Object)null) { _wardLight.intensity = 0f; } ((MonoBehaviour)this).StopCoroutine("Recharge"); ((MonoBehaviour)this).StartCoroutine("Recharge"); } private IEnumerator Recharge() { float elapsed = 0f; while (elapsed < _rechargeDuration) { elapsed += Time.deltaTime; _charge = Mathf.Min(1f, elapsed / _rechargeDuration); if ((Object)(object)_wardLight != (Object)null) { _wardLight.intensity = _baseIntensity * _charge; } yield return null; } _charge = 1f; if ((Object)(object)_wardLight != (Object)null) { _wardLight.intensity = _baseIntensity; } } private void PlayTickEffect() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (playFlash) { _wardArea.m_flashEffect.Create(((Component)this).transform.position, Quaternion.identity, (Transform)null, 1f, -1); } if (TickSoundPrefab != null) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(TickSoundPrefab) : null); if ((Object)(object)val != (Object)null) { Object.Instantiate<GameObject>(val, ((Component)this).transform.position, Quaternion.identity); } } } } public static class WardConfig { public static ConfigEntry<float> ElementalTickInterval; public static ConfigEntry<string> ElementalExcludedFactions; public static ConfigEntry<float> FireDamage; public static ConfigEntry<float> FireRadius; public static ConfigEntry<string> FireIngredients; public static ConfigEntry<float> FrostDamage; public static ConfigEntry<float> FrostRadius; public static ConfigEntry<string> FrostIngredients; public static ConfigEntry<float> PoisonDamage; public static ConfigEntry<float> PoisonRadius; public static ConfigEntry<string> PoisonIngredients; public static ConfigEntry<float> LightningDamage; public static ConfigEntry<float> LightningRadius; public static ConfigEntry<string> LightningIngredients; public static ConfigEntry<float> SpiritDamage; public static ConfigEntry<float> SpiritRadius; public static ConfigEntry<string> SpiritIngredients; public static ConfigEntry<float> RepairInterval; public static ConfigEntry<float> RepairRadius; public static ConfigEntry<string> RepairIngredients; public static ConfigEntry<float> HealInterval; public static ConfigEntry<float> HealAmount; public static ConfigEntry<float> HealRadius; public static ConfigEntry<string> HealIngredients; private const string IngredientsDesc = "Crafting ingredients (comma-separated, format: ItemName:Amount)."; public static void Init(ConfigFile cfg) { ElementalTickInterval = cfg.Bind<float>("Elemental", "TickInterval", 3f, "Seconds between each elemental damage tick."); ElementalExcludedFactions = cfg.Bind<string>("Elemental", "ExcludedFactions", "Players,Dverger", "Factions excluded from elemental damage (comma-separated).\nPossible values: Players, AnimaI, ForestMonsters, Undead, Demon, MountainMonsters, SeaMonsters, PlainsMonsters, Boss"); FireDamage = cfg.Bind<float>("Ward_Fire", "Damage", 10f, "Fire damage per tick."); FireRadius = cfg.Bind<float>("Ward_Fire", "Radius", 32f, "Fire ward radius (meters)."); FireIngredients = cfg.Bind<string>("Ward_Fire", "Ingredients", "FineWood:5,TrophySurtling:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); FrostDamage = cfg.Bind<float>("Ward_Frost", "Damage", 10f, "Frost damage per tick."); FrostRadius = cfg.Bind<float>("Ward_Frost", "Radius", 32f, "Frost ward radius (meters)."); FrostIngredients = cfg.Bind<string>("Ward_Frost", "Ingredients", "FineWood:5,TrophyHatchling:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); PoisonDamage = cfg.Bind<float>("Ward_Poison", "Damage", 10f, "Poison damage per tick."); PoisonRadius = cfg.Bind<float>("Ward_Poison", "Radius", 32f, "Poison ward radius (meters)."); PoisonIngredients = cfg.Bind<string>("Ward_Poison", "Ingredients", "FineWood:5,TrophyBlob:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); LightningDamage = cfg.Bind<float>("Ward_Lightning", "Damage", 10f, "Lightning damage per tick."); LightningRadius = cfg.Bind<float>("Ward_Lightning", "Radius", 32f, "Lightning ward radius (meters)."); LightningIngredients = cfg.Bind<string>("Ward_Lightning", "Ingredients", "FineWood:5,Crystal:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); SpiritDamage = cfg.Bind<float>("Ward_Spirit", "Damage", 10f, "Spirit damage per tick."); SpiritRadius = cfg.Bind<float>("Ward_Spirit", "Radius", 32f, "Spirit ward radius (meters)."); SpiritIngredients = cfg.Bind<string>("Ward_Spirit", "Ingredients", "FineWood:5,TrophyGhost:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); RepairInterval = cfg.Bind<float>("Ward_Repair", "Interval", 10f, "Seconds between each automatic repair."); RepairRadius = cfg.Bind<float>("Ward_Repair", "Radius", 32f, "Repair ward radius (meters)."); RepairIngredients = cfg.Bind<string>("Ward_Repair", "Ingredients", "FineWood:5,YggdrasilWood:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); HealInterval = cfg.Bind<float>("Ward_Healing", "Interval", 10f, "Seconds between each automatic heal."); HealAmount = cfg.Bind<float>("Ward_Healing", "HealAmount", 10f, "Hit points restored per tick."); HealRadius = cfg.Bind<float>("Ward_Healing", "Radius", 32f, "Healing ward radius (meters)."); HealIngredients = cfg.Bind<string>("Ward_Healing", "Ingredients", "FineWood:5,TrophyGreydwarfShaman:11,Eitr:1", "Crafting ingredients (comma-separated, format: ItemName:Amount)."); } public static HashSet<Faction> GetExcludedFactions() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) HashSet<Faction> hashSet = new HashSet<Faction>(); string[] array = ElementalExcludedFactions.Value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { if (Enum.TryParse<Faction>(array[i].Trim(), out Faction result)) { hashSet.Add(result); } } return hashSet; } public static RequirementConfig[] ParseIngredients(string value) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Trim().Split(new char[1] { ':' }); if (array2.Length == 2 && int.TryParse(array2[1].Trim(), out var result)) { list.Add(new RequirementConfig { Item = array2[0].Trim(), Amount = result, Recover = true }); } } return list.ToArray(); } } public static class WardFactory { private static readonly Dictionary<string, Dictionary<string, string>> _color_properties = new Dictionary<string, Dictionary<string, string>> { { "default", new Dictionary<string, string> { { "Guardstone_OdenGlow_mat", "_EmissionColor" } } }, { "sparcs", new Dictionary<string, string> { { "gnista", "_Color" } } } }; public static void RegisterWards() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) RegisterElemental("piece_ward_fire", "$hw_ward_fire", "$hw_ward_fire_desc", new Color(1f, 0.15f, 0f), ElementalWardBehavior.Element.Fire, WardConfig.FireRadius.Value, WardConfig.ParseIngredients(WardConfig.FireIngredients.Value)); RegisterElemental("piece_ward_frost", "$hw_ward_frost", "$hw_ward_frost_desc", new Color(0.85f, 0.95f, 1f), ElementalWardBehavior.Element.Frost, WardConfig.FrostRadius.Value, WardConfig.ParseIngredients(WardConfig.FrostIngredients.Value)); RegisterElemental("piece_ward_poison", "$hw_ward_poison", "$hw_ward_poison_desc", new Color(0.1f, 0.9f, 0.1f), ElementalWardBehavior.Element.Poison, WardConfig.PoisonRadius.Value, WardConfig.ParseIngredients(WardConfig.PoisonIngredients.Value)); RegisterElemental("piece_ward_lightning", "$hw_ward_lightning", "$hw_ward_lightning_desc", new Color(0.2f, 0.75f, 1f), ElementalWardBehavior.Element.Lightning, WardConfig.LightningRadius.Value, WardConfig.ParseIngredients(WardConfig.LightningIngredients.Value)); RegisterElemental("piece_ward_spirit", "$hw_ward_spirit", "$hw_ward_spirit_desc", new Color(0.65f, 0.1f, 1f), ElementalWardBehavior.Element.Spirit, WardConfig.SpiritRadius.Value, WardConfig.ParseIngredients(WardConfig.SpiritIngredients.Value)); RegisterSpecial<RepairWardBehavior>("piece_ward_repair", "$hw_ward_repair", "$hw_ward_repair_desc", new Color(1f, 0.45f, 0f), WardConfig.RepairRadius.Value, WardConfig.ParseIngredients(WardConfig.RepairIngredients.Value)); RegisterSpecial<HealingWardBehavior>("piece_ward_healing", "$hw_ward_healing", "$hw_ward_healing_desc", new Color(1f, 0.35f, 0.65f), WardConfig.HealRadius.Value, WardConfig.ParseIngredients(WardConfig.HealIngredients.Value)); PrefabManager.OnVanillaPrefabsAvailable -= RegisterWards; } private static void RegisterElemental(string prefabName, string displayName, string desc, Color lightColor, ElementalWardBehavior.Element element, float radius, params RequirementConfig[] reqs) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneWard(prefabName, lightColor, displayName, radius); if (!((Object)(object)val == (Object)null)) { val.AddComponent<ElementalWardBehavior>().DamageElement = element; val.GetComponent<ElementalWardBehavior>().Radius = radius; RegisterPiece(val, displayName, desc, reqs); } } private static void RegisterSpecial<T>(string prefabName, string displayName, string desc, Color lightColor, float radius, params RequirementConfig[] reqs) where T : WardBehavior { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneWard(prefabName, lightColor, displayName, radius); if (!((Object)(object)val == (Object)null)) { val.AddComponent<T>(); val.GetComponent<T>().Radius = radius; RegisterPiece(val, displayName, desc, reqs); } } private static GameObject? CloneWard(string name, Color lightColor, string displayName, float radius) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_015d: Unknown result type (might be due to invalid IL or missing references) GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, "guard_stone"); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogError((object)("[HelpfullWards] Failed to clone guard_stone for: " + name)); return null; } PrivateArea component = val.GetComponent<PrivateArea>(); HelpfulWardArea helpfulWardArea = val.AddComponent<HelpfulWardArea>(); helpfulWardArea.m_name = displayName; helpfulWardArea.m_radius = radius; helpfulWardArea.m_enabledByDefault = true; helpfulWardArea.m_enabledEffect = component.m_enabledEffect; helpfulWardArea.m_model = component.m_model; helpfulWardArea.m_areaMarker = component.m_areaMarker; helpfulWardArea.m_flashEffect = component.m_flashEffect; helpfulWardArea.m_activateEffect = component.m_activateEffect; helpfulWardArea.m_deactivateEffect = component.m_deactivateEffect; Object.DestroyImmediate((Object)(object)component); Light[] componentsInChildren = val.GetComponentsInChildren<Light>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].color = lightColor; } Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren2) { if (!_color_properties.ContainsKey(((Object)val2).name)) { continue; } Material[] sharedMaterials = val2.sharedMaterials; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null) && _color_properties[((Object)val2).name].ContainsKey(((Object)sharedMaterials[j]).name)) { string text = _color_properties[((Object)val2).name][((Object)sharedMaterials[j]).name]; Material val3 = new Material(sharedMaterials[j]); val3.SetColor(text, lightColor); sharedMaterials[j] = val3; flag = true; } } if (flag) { val2.sharedMaterials = sharedMaterials; } } return val; } private static void RegisterPiece(GameObject go, string displayName, string desc, RequirementConfig[] reqs) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown PieceManager.Instance.AddPiece(new CustomPiece(go, true, new PieceConfig { Name = displayName, Description = desc, PieceTable = "_HammerPieceTable", Category = "Misc", CraftingStation = "piece_workbench", Requirements = reqs })); } } }