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 ExtendedBosses v0.8.17
ExtendedBosses.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace ExtendedBosses; internal enum ActKind { Wave, Lieutenant, Nest, Totem, Marks, Charge, Shield, Resist, Cycle, Fusion, Seeds, HitEffect, Fixate, Cocoon, Hazard, Roar } internal class CycleVariant { public string Id; public string Say; public Dictionary<DamageType, float> Mods; public float Other = 1f; public bool Back; public float MeleeFactor = 1f; public float MeleeRange = 5f; public float Retaliate; public DamageType RetaliateType = (DamageType)256; public float RangedFactor = 1f; public bool GroundedOnly; public float ThornsPercent; public float ThornsMin; public float RegenPercent; public DamageType RegenStopType = (DamageType)64; public float RegenStopSeconds = 3f; public bool Adapt; public float AdaptFactor = 0.6f; public float AdaptOthers = 1.1f; public float Lifesteal; public string EndKey; } internal class Act { public ActKind Kind; public string[] Prefabs; public string[] NightPrefabs; public string Fallback = "BonePileSpawner"; public float Count = 1f; public int ExtraFrom; public int Level = 1; public float HpMul = 1f; public int Role; public float Lifetime; public bool InWater; public string Prop; public string StrikeFx; public float Interval = 12f; public int MaxAlive = 3; public int ExtraAliveFrom = 4; public int AlivePerPlayer; public float MarkRange; public float Damage; public DamageType DamageType = (DamageType)128; public string MarkKey; public string Creature; public int CreatureCount = 4; public float RingRadius = 3f; public float Duration; public Dictionary<DamageType, float> Mods; public float CooldownMin; public float CooldownMax; public float Delay; public List<CycleVariant> Variants; public string EndKey; public float Heal; public string Gate; public bool AnyProp; public bool ScaleAsAdds; public float Chance; public string Effect; public float Radius; public bool Land; public bool NoDrop; } internal class PhaseDef { public float Pct; public string Say; public List<Act> Acts = new List<Act>(); } internal class Loot { public string Prefab; public int Min; public int Max; public bool PerPlayer; public float StackFraction; public Loot(string prefab, int min, int max, bool perPlayer) { Prefab = prefab; Min = min; Max = max; PerPlayer = perPlayer; } public static Loot Stack(string prefab, float fraction) { Loot loot = new Loot(prefab, 0, 0, perPlayer: false); loot.StackFraction = fraction; return loot; } } internal class RewardDef { public List<Loot> Valuables = new List<Loot>(); public List<Loot> NextBiome = new List<Loot>(); public string[] Gear = new string[0]; public string[] NextGear = new string[0]; } internal class BossDef { public string Prefab; public int Hash; public string Section; public List<PhaseDef> Phases = new List<PhaseDef>(); public RewardDef Reward = new RewardDef(); public ConfigEntry<string> CfgMode; public ConfigEntry<string> CfgProfile; public Action<ExtendedBossesPlugin, BossDef> BindExtra; public ConfigEntry<string> CfgTotemPrefab; public ConfigEntry<string> CfgNestPrefab; public ConfigEntry<string> CfgMarkPrefab; public ConfigEntry<string> CfgMarkEffect; public ConfigEntry<string> CfgMarkCreature; public ConfigEntry<float> CfgMarkDamage; public ConfigEntry<float> CfgChargeInterval; public ConfigEntry<float> CfgChargeSpeed; public ConfigEntry<float> CfgChargeDuration; public ConfigEntry<string> CfgCycleVariant; public ConfigEntry<float> CfgCycleDuration; public ConfigEntry<float> CfgCycleCdMin; public ConfigEntry<float> CfgCycleCdMax; public ConfigEntry<float> CfgCycleDelay; public ConfigEntry<float> CfgBackArc; public ConfigEntry<float> CfgCycleMelee; public ConfigEntry<float> CfgCycleRetaliate; public ConfigEntry<float> CfgCycleRanged; public ConfigEntry<float> CfgCycleThorns; public ConfigEntry<float> CfgRegen; public ConfigEntry<float> CfgAdaptFactor; public ConfigEntry<float> CfgAdaptOthers; public ConfigEntry<float> CfgLifesteal; public ConfigEntry<float> CfgHealthPerPlayer; public ConfigEntry<int> CfgCapSolo; public ConfigEntry<int> CfgCapPerPlayer; public ConfigEntry<float> CfgEggHatch; public bool CapSummons; public ConfigEntry<float> CfgHealPercent; public ConfigEntry<float> CfgMarkInterval; public ConfigEntry<float> CfgRoarInterval; public ConfigEntry<float> CfgRoarRadius; public ConfigEntry<float> CfgRoarDamage; public string FlyerPrefab; public ConfigEntry<float> CfgFlyerInterval; public ConfigEntry<int> CfgFlyerMax; public float CycleCdMinDefault = 50f; public float CycleCdMaxDefault = 70f; public readonly Dictionary<string, ConfigEntry<bool>> Gates = new Dictionary<string, ConfigEntry<bool>>(); public ConfigEntry<float> CfgFusionInterval; public ConfigEntry<float> CfgFusionHeal; } [BepInPlugin("j1ga.extendedbosses", "Extended Bosses", "0.8.17")] public class ExtendedBossesPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(EggHatch), "CheckSpawn")] private static class EggHatch_CheckSpawn_Patch { private static bool Prefix(EggHatch __instance) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null) { return true; } try { return instance.EggCheck(__instance); } catch (Exception e) { instance.Fail("EggHatch.CheckSpawn", e); return true; } } } [HarmonyPatch(typeof(SpawnAbility), "Setup")] private static class SpawnAbility_Setup_Patch { private static bool Prefix(SpawnAbility __instance, Character owner) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || instance._fights.Count == 0) { return true; } try { if (instance.SummonAllowed(__instance, owner)) { return true; } if (!DestroyNetObject(((Component)__instance).gameObject)) { Object.Destroy((Object)(object)((Component)__instance).gameObject); } return false; } catch (Exception e) { instance.Fail("SpawnAbility.Setup", e); return true; } } } [HarmonyPatch(typeof(BaseAI), "UpdateRegeneration")] private static class BaseAI_UpdateRegeneration_Patch { private static bool Prefix(Character ___m_character) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)___m_character == (Object)null || instance._fights.Count == 0 || !___m_character.IsBoss()) { return true; } try { FightRt fightRt = instance.RtIfRunning(___m_character); if (fightRt == null || !instance.IsModMode(fightRt.Def)) { return true; } ZDO val = Zdo((Component)(object)___m_character); return val == null || val.GetInt(KPhase, 0) == 0; } catch (Exception e) { instance.Fail("BaseAI.UpdateRegeneration", e); return true; } } } [HarmonyPatch(typeof(SpawnArea), "SpawnOne")] private static class SpawnArea_SpawnOne_Patch { private static bool Prefix(SpawnArea __instance, ref bool __result) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null) { return true; } try { if (instance.NestMaySpawn(__instance)) { return true; } __result = false; return false; } catch (Exception e) { instance.Fail("SpawnArea.SpawnOne", e); return true; } } } [HarmonyPatch(typeof(Projectile), "OnHit")] private static class Projectile_OnHit_Patch { private static void Postfix(Projectile __instance, Vector3 hitPoint) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || instance._fights.Count == 0) { return; } try { instance.OnProjectileHit(__instance, hitPoint); } catch (Exception e) { instance.Fail("Projectile.OnHit", e); } } } private class Strike { public ZDOID Target; public float At; public Act Act; } private class FightRt { public ZDOID BossId; public BossDef Def; public Character Boss; public bool Seen; public float NextMark; public float NextFlyer; public float BusyUntil; public readonly List<Strike> Strikes = new List<Strike>(); public float NextCharge; public float ChargeEnd; public bool Charging; public float BaseSpeed; public float BaseRun; public readonly Dictionary<int, float> TotemNext = new Dictionary<int, float>(); public float NoPlayersSince = -1f; public bool CleanedForVanilla; public bool ShieldActive; public bool WindowActive; public Act ResistAct; public Act CycleAct; public CycleVariant CycleVar; public float NextFusion; public float NextTrim; public float NextShieldReminder; public readonly Dictionary<ZDOID, float> RetaliateAt = new Dictionary<ZDOID, float>(); public readonly Dictionary<DamageType, float> TypeDmg = new Dictionary<DamageType, float>(); public readonly Dictionary<DamageType, float> LastHitBy = new Dictionary<DamageType, float>(); public DamageType AdaptType; public int TotemsAlive; public int Healers; public int Guards; public float NextFix; public float FixUntil; public ZDOID FixTarget = ZDOID.None; public float NextHazard; public float NextRoar; public float RoarAt; public float NextSeed; public float CocoonUntil; public float CocoonReady; public bool CocoonActive; public Vector3 LastPos; public bool HasLastPos; public readonly Dictionary<ZDOID, float> Threat = new Dictionary<ZDOID, float>(); public ZDOID ThreatTarget = ZDOID.None; public float ThreatSince; } private sealed class PhaseMemo { public int Resets; public int Mask; } private struct Candidate { public long Uid; public Vector3 Pos; public Version Ver; public bool Host; } [HarmonyPatch(typeof(Piece), "DropResources")] private static class Piece_DropResources_Patch { private static bool Prefix(Piece __instance) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null) { return true; } try { return !NoDropObject((Component)(object)__instance); } catch (Exception e) { instance.Fail("Piece.DropResources", e); return true; } } } [HarmonyPatch(typeof(DropOnDestroyed), "OnDestroyed")] private static class DropOnDestroyed_OnDestroyed_Patch { private static bool Prefix(DropOnDestroyed __instance) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null) { return true; } try { return !NoDropObject((Component)(object)__instance); } catch (Exception e) { instance.Fail("DropOnDestroyed.OnDestroyed", e); return true; } } } [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class Character_RPC_Damage_Patch { private static void Prefix(Character __instance, HitData hit, out float __state) { __state = -1f; ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || hit == null) { return; } try { if (__instance.IsPlayer()) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Character attacker = hit.GetAttacker(); if ((Object)(object)attacker != (Object)null && attacker.IsBoss() && instance.LifestealPct(attacker) > 0f) { __state = __instance.GetHealth(); } } } else { if (!IsOwner((Component)(object)__instance)) { return; } ZDO val = Zdo((Component)(object)__instance); if (val == null) { return; } float num = 1f; if (__instance.IsBoss()) { BossDef bossDef = instance.BossOf(val); if (bossDef != null && instance.IsModMode(bossDef)) { instance.RecordHit(__instance, hit); float totalDamage = hit.GetTotalDamage(); instance.ApplyResist(__instance, hit); instance.ApplyCycle(__instance, hit); hit.ApplyModifier(instance.MechFactor(__instance, bossDef)); float totalDamage2 = hit.GetTotalDamage(); float num2 = instance.Sv(instance._cfgMinDamage); if (totalDamage > 0.01f && totalDamage2 > 0.0001f && totalDamage2 < totalDamage * num2) { hit.ApplyModifier(totalDamage * num2 / totalDamage2); } num *= instance.ScaleFactor(__instance, bossDef); __state = __instance.GetHealth(); } } float num3 = val.GetFloat(KHpMul, 1f); if (num3 > 0.01f && Mathf.Abs(num3 - 1f) > 0.001f) { num /= num3; } if (Mathf.Abs(num - 1f) > 0.001f) { hit.ApplyModifier(num); } } } catch (Exception e) { instance.Fail("RPC_Damage", e); } } private static void Postfix(Character __instance, HitData hit, float __state) { if (__state < 0f) { return; } ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null || hit == null) { return; } try { float num = __state - __instance.GetHealth(); if (__instance.IsPlayer()) { Character attacker = hit.GetAttacker(); if ((Object)(object)attacker != (Object)null && num > 0f) { instance.Lifesteal(attacker, num); } } else { instance.AddThreat(__instance, hit.GetAttacker(), num); } } catch (Exception e) { instance.Fail("RPC_Damage threat", e); } } } [HarmonyPatch(typeof(Character), "Damage")] private static class Character_Damage_Patch { private static void Prefix(Character __instance, HitData hit) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || hit == null || instance._fights.Count == 0) { return; } try { if (__instance.IsPlayer()) { Character attacker = hit.GetAttacker(); if (!((Object)(object)attacker == (Object)null) && attacker.IsBoss() && IsOwner((Component)(object)attacker)) { instance.ApplyHitEffect(attacker, hit); instance.FixateBonus(attacker, __instance, hit); } } } catch (Exception e) { instance.Fail("Character.Damage", e); } } } [HarmonyPatch(typeof(Character), "Awake")] private static class Character_Awake_Patch { private static void Postfix(Character __instance) { //IL_0031: 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) ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors || (Object)(object)__instance == (Object)null) { return; } try { ZDO val = Zdo((Component)(object)__instance); if (val != null && val.GetZDOID(KBossPair) != ZDOID.None) { __instance.m_group = "extendedbosses"; } } catch (Exception e) { instance.Fail("Character.Awake", e); } } } [HarmonyPatch(typeof(Character), "OnDeath")] private static class Character_OnDeath_Patch { private static void Prefix(Character __instance) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || !__instance.IsBoss()) { return; } try { if (!IsOwner((Component)(object)__instance)) { return; } BossDef bossDef = instance.BossOf(Zdo((Component)(object)__instance)); if (bossDef != null && instance.IsModMode(bossDef)) { FightRt fightRt = instance.RtIfRunning(__instance); if (fightRt != null) { instance.StopCharge(fightRt); } instance.DropRewards(__instance, bossDef); if (instance.Sb(instance._cfgCleanupOnDeath)) { int num = instance.Cleanup(__instance); instance.Debug(bossDef.Prefab + " died: removed " + num + " add(s)/nest(s)"); } } } catch (Exception e) { instance.Fail("OnDeath", e); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake_Patch { private static void Postfix() { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.SelfCheck(); } catch (Exception e) { instance.Fail("self-check", e); } } } private enum Need { Creature, Nest, Totem, Prop, Aoe, Effect, Item, Status } private class Circle { public GameObject Go; public LineRenderer Line; public Transform Follow; public Vector3 Pos; public float Radius; public float Until; } private sealed class StatusCache { public string Text; public float At; } [HarmonyPatch(typeof(EnemyHud), "UpdateHuds")] private static class EnemyHud_UpdateHuds_Patch { private static void Postfix(EnemyHud __instance) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null) { return; } try { instance.DecorateBossHuds(__instance); } catch (Exception e) { instance.Fail("EnemyHud.UpdateHuds", e); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] private static class ZNet_Disconnect_Patch { private static void Postfix(ZNetPeer peer) { ExtendedBossesPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && peer != null) { instance._moddedPeers.Remove(peer.m_uid); instance._peerVersions.Remove(peer.m_uid); } } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNet_Awake_Patch { private static void Postfix() { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null) { return; } try { instance.RegisterRpc(); } catch (Exception e) { instance.Fail("ZNet.Awake", e); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class ZNet_RPC_PeerInfo_Patch { private static void Postfix(ZNet __instance, ZRpc rpc) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || instance._disabledByErrors) { return; } try { instance.OnPeerInfo(__instance, rpc); } catch (Exception e) { instance.Fail("ZNet.RPC_PeerInfo", e); } } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static class ZNet_OnDestroy_Patch { private static void Postfix() { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null) { return; } try { ((MonoBehaviour)instance).StopAllCoroutines(); instance.ClearServerValues(); instance.RestoreAllCharges(); instance._fights.Clear(); instance.ClearCircles(); instance.ClearGlows(); instance.ClearPins(); instance._helloSent = false; instance._moddedPeers.Clear(); instance._peerVersions.Clear(); } catch (Exception e) { instance.Fail("ZNet.OnDestroy", e); } } } [HarmonyPatch(typeof(MonsterAI), "UpdateTarget")] private static class MonsterAI_UpdateTarget_Patch { [HarmonyPriority(800)] private static void Postfix(MonsterAI __instance) { ExtendedBossesPlugin instance = Instance; if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || instance._fights.Count == 0) { return; } try { Character component = ((Component)__instance).GetComponent<Character>(); if (!((Object)(object)component == (Object)null) && component.IsBoss()) { instance.PickThreatTarget(__instance, component); } } catch (Exception e) { instance.Fail("UpdateTarget", e); } } } internal const int RoleHealer = 1; internal const int RoleFuse = 2; internal const int RoleGuard = 3; internal const int RoleLieutenant = 4; internal const string CycleRandom = "Random"; internal const string CycleAuto = "Auto"; internal const string ProfileLight = "Light"; internal const string ProfileRaid = "Raid"; internal const string ProfileHard = "Hard"; internal const string ProfileDefault = "Default"; internal const string ModeMod = "Mod"; internal const string ModeVanilla = "Vanilla"; private const int CurrentConfigVersion = 4; private const float ReloadDebounce = 1f; public const string Guid = "j1ga.extendedbosses"; public const string Name = "Extended Bosses"; public const string Version = "0.8.17"; internal const string RaidGroup = "extendedbosses"; private const int MaxErrors = 25; private const float TickInterval = 0.25f; private const float RoarWarn = 4f; internal const string KBoss = "j1ga.extendedbosses.boss"; private const int NestCode = -1; private const int SeedCode = -2; private const float FuseReach = 3.5f; private const int FlyerSrc = -3; private const string GlowName = "extendedbosses_glow"; private const float NestRingRadius = 2.5f; private const float HandoffInterval = 2f; private const string FxRpc = "j1ga.extendedbosses.fx"; internal const int FxMark = 1; internal const int FxStrike = 2; private const int CircleSegments = 48; private const float StatusRefresh = 0.5f; private const string HelloRpc = "j1ga.extendedbosses.hello"; private const string AnnounceRpc = "j1ga.extendedbosses.announce"; private const string MessageRpc = "j1ga.extendedbosses.msg"; private const int CenterLines = 3; private const float VanillaCenterFade = 4f; private const string SyncRpc = "j1ga.extendedbosses.config"; private const int SyncVersion = 1; private readonly List<BossDef> _bosses = new List<BossDef>(); private readonly Dictionary<int, BossDef> _bossByHash = new Dictionary<int, BossDef>(); private ConfigEntry<int> _cfgCapBase; private ConfigEntry<int> _cfgCapPerPlayer; private ConfigEntry<float> _cfgCapRadius; private ConfigEntry<float> _cfgTrimAt; private ConfigEntry<float> _cfgWaveLifetime; private static MethodInfo _miHatch; private ConfigEntry<bool> _cfgEnabled; private ConfigEntry<bool> _cfgDebug; private ConfigEntry<string> _cfgProfile; private ConfigEntry<string> _cfgAnnounce; private ConfigEntry<float> _cfgScalingRange; private ConfigEntry<float> _cfgHealthPerPlayer; private ConfigEntry<int> _cfgMaxScalingPlayers; private ConfigEntry<float> _cfgBaseHealth; private ConfigEntry<float> _cfgHardHealth; private ConfigEntry<float> _cfgSoloAdds; private ConfigEntry<float> _cfgAddsPerPlayer; private ConfigEntry<float> _cfgHardAdds; private ConfigEntry<int> _cfgLieutenantStarPlayers; private ConfigEntry<int> _cfgAddStarPlayers; private ConfigEntry<float> _cfgSoloHealth; private ConfigEntry<float> _cfgSoloLieutenant; private ConfigEntry<bool> _cfgWaves; private ConfigEntry<bool> _cfgNests; private ConfigEntry<bool> _cfgLieutenants; private ConfigEntry<bool> _cfgMarks; private ConfigEntry<bool> _cfgSpecials; private ConfigEntry<bool> _cfgShield; private ConfigEntry<bool> _cfgHealers; private ConfigEntry<bool> _cfgResist; private ConfigEntry<bool> _cfgThreat; private ConfigEntry<bool> _cfgCleanupOnDeath; private ConfigEntry<bool> _cfgCleanupOnDisable; private ConfigEntry<float> _cfgSpawnRadiusMin; private ConfigEntry<float> _cfgSpawnRadiusMax; private ConfigEntry<float> _cfgMarkDelay; private ConfigEntry<float> _cfgMarkInterval; private ConfigEntry<float> _cfgMarkDamage; private ConfigEntry<bool> _cfgRewards; private ConfigEntry<int> _cfgQualityMin; private ConfigEntry<int> _cfgQualityMax; private ConfigEntry<float> _cfgPlayersPerItem; private ConfigEntry<int> _cfgGearMinPlayers; private ConfigEntry<float> _cfgValuables; private ConfigEntry<bool> _cfgReset; private ConfigEntry<float> _cfgResetRadius; private ConfigEntry<float> _cfgResetSeconds; private ConfigEntry<bool> _cfgShowCircles; private ConfigEntry<float> _cfgMessageDuration; private ConfigEntry<float> _cfgShieldFactor; private ConfigEntry<float> _cfgHardShieldFactor; private ConfigEntry<float> _cfgWindowSeconds; private ConfigEntry<float> _cfgWindowMultiplier; private ConfigEntry<float> _cfgHealPercent; private ConfigEntry<float> _cfgHealRange; private ConfigEntry<float> _cfgLeash; private ConfigEntry<float> _cfgSwitchMargin; private ConfigEntry<float> _cfgHoldSeconds; private ConfigEntry<float> _cfgThreatDecay; private ConfigEntry<float> _cfgOutOfLeashHalfLife; private ConfigEntry<float> _cfgShieldMax; private ConfigEntry<float> _cfgShieldReminder; private ConfigEntry<float> _cfgMinDamage; private ConfigEntry<float> _cfgFixateBonus; private ConfigEntry<float> _cfgAimChance; private ConfigEntry<float> _cfgAimRange; private ConfigEntry<int> _cfgConfigVersion; private static readonly string[] Profiles = new string[3] { "Light", "Raid", "Hard" }; private static readonly string[] BossProfiles = new string[4] { "Default", "Light", "Raid", "Hard" }; private static readonly string[] Modes = new string[2] { "Mod", "Vanilla" }; private ConfigEntry<bool> _cfgWatchFile; private FileSystemWatcher _watcher; private volatile bool _fileChanged; private float _reloadAt; private float _lastSettingChange = -100f; private bool _reloading; public static ExtendedBossesPlugin Instance; private Harmony _harmony; private int _errorCount; private bool _disabledByErrors; private readonly HashSet<string> _loggedErrors = new HashSet<string>(); private float _nextTick; private float _nextOrphanScan; private static FieldInfo _fiProjectileOwner; internal static readonly int KPhase = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.phase"); internal static readonly int KResets = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.resets"); internal static readonly int KBaseMax = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.basemax"); internal static readonly int KHpScale = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.hpscale"); internal static readonly int KTotems = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.totems"); internal static readonly int KShieldAct = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.shield"); internal static readonly int KResistAct = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.resist"); internal static readonly int KResistUntil = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.resistuntil"); internal static readonly int KWindowUntil = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.window"); internal static readonly int KShieldSince = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.shieldsince"); internal static readonly int KCycleAct = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cycle"); internal static readonly int KCycleStartAt = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cyclestart"); internal static readonly int KCycleStarted = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cycleon"); internal static readonly int KCycleUntil = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cycleuntil"); internal static readonly int KCycleNext = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cyclenext"); internal static readonly int KCycleAdapt = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cycleadapt"); internal static readonly int KCycleKind = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.cyclekind"); internal static readonly KeyValuePair<int, int> KBossPair = ZDO.GetHashZDOID("j1ga.extendedbosses.boss"); internal static readonly int KHpMul = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.hpmul"); internal static readonly int KSrc = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.src"); internal static readonly int KRole = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.role"); internal static readonly int KExpire = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.expire"); internal static readonly int KBorn = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.born"); internal static readonly int KHatchAt = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.hatchat"); internal static readonly int KFuseHeal = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.fuseheal"); private readonly Dictionary<ZDOID, FightRt> _fights = new Dictionary<ZDOID, FightRt>(); private readonly List<Character> _tmpBosses = new List<Character>(); private readonly List<ZDOID> _tmpIds = new List<ZDOID>(); private int _forcePlayers; private readonly Dictionary<ZDOID, PhaseMemo> _phaseMemo = new Dictionary<ZDOID, PhaseMemo>(); private readonly List<GameObject> _tmpExpired = new List<GameObject>(); private readonly List<Character> _tmpTrim = new List<Character>(); private FieldInfo _instancesField; internal static readonly int KNoDrop = StringExtensionMethods.GetStableHashCode("j1ga.extendedbosses.nodrop"); private ConfigEntry<bool> _cfgHighlight; private float _nextGlowScan; private readonly Dictionary<int, GameObject> _glows = new Dictionary<int, GameObject>(); private readonly List<int> _tmpGlowIds = new List<int>(); private static readonly int KTauntBy = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.holdby"); private static readonly int KTauntUntil = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.holduntil"); private readonly Dictionary<long, Version> _peerVersions = new Dictionary<long, Version>(); private readonly List<ZDO> _handoffNear = new List<ZDO>(); private readonly HashSet<ZDOID> _handoffSeen = new HashSet<ZDOID>(); private float _nextHandoff; private readonly List<Candidate> _candidates = new List<Candidate>(); private int _checkOk; private List<string> _checkProblems = new List<string>(); private static int _interiorMask; private static readonly Dictionary<string, GameObject> _attackPrefabs = new Dictionary<string, GameObject>(); private readonly List<Circle> _circles = new List<Circle>(); private Material _circleMat; private ConfigEntry<bool> _cfgStatusLine; private ConfigEntry<bool> _cfgMapPins; private readonly Dictionary<Character, StatusCache> _status = new Dictionary<Character, StatusCache>(); private float _nextPinScan; private Minimap _pinMap; private readonly Dictionary<ZDOID, PinData> _pins = new Dictionary<ZDOID, PinData>(); private readonly HashSet<ZDOID> _tmpPinSeen = new HashSet<ZDOID>(); private readonly List<ZDOID> _tmpPinGone = new List<ZDOID>(); private static FieldInfo _fiHuds; private static FieldInfo _fiHudChar; private static FieldInfo _fiHudName; private static MethodInfo _miAddPin; private static readonly Dictionary<string, string[]> Texts = new Dictionary<string, string[]> { { "eikthyr.80", new string[2] { "{0}: Herd, to me!", "{0}: Стадо, ко мне!" } }, { "eikthyr.60", new string[2] { "{0} lowers the antlers - beware the charge!", "{0} пригибает рога — берегитесь рывка!" } }, { "eikthyr.50", new string[2] { "{0}: Rise, bones! (smash the skull pile)", "{0}: Кости, встаньте! (разбейте груду черепов)" } }, { "eikthyr.30", new string[2] { "{0}: The sky answers me! (the marked one - move away from the others)", "{0}: Небо, ответь мне! (отмеченный — отойди от остальных)" } }, { "eikthyr.15", new string[2] { "{0} calls the leader of the herd!", "{0} призывает вожака стада!" } }, { "eikthyr.mark", new string[2] { "{0} marks {1} for lightning - spread out!", "{0} метит молнией: {1} — разойдитесь!" } }, { "elder.85", new string[2] { "{0}: Forest, hear me! (destroy the nest)", "{0}: Лес, услышь меня! (разрушьте гнездо)" } }, { "elder.70", new string[2] { "{0}: More of my children! (nests - and roots stir underfoot)", "{0}: Ещё мои дети! (гнёзда — и корни под ногами)" } }, { "elder.55", new string[2] { "{0}: My nests shield me! (destroy them all)", "{0}: Гнёзда укроют меня! (разрушьте их все)" } }, { "elder.bark.sap", new string[2] { "{0}: the bark swells with sap - fire is useless, chop with axes!", "{0}: кора набухла соком — огонь бесполезен, рубите топорами!" } }, { "elder.bark.back", new string[2] { "{0} is covered in living bark - only blows to the back hurt! Tank, hold it facing you!", "{0}: живая кора — ранят только удары в спину! Танк, держите босса лицом к себе!" } }, { "elder.bark.end", new string[2] { "{0}: the bark cracks - hit with anything!", "{0}: кора трескается — бейте чем угодно!" } }, { "elder.45", new string[2] { "{0} calls a troll!", "{0} призывает тролля!" } }, { "elder.30", new string[2] { "{0} wakes a bear!", "{0} будит медведя!" } }, { "elder.20", new string[2] { "{0} calls the elite - kill the shamans first, they heal the boss!", "{0} зовёт элиту — сначала убейте шаманов, они лечат босса!" } }, { "elder.10", new string[2] { "{0}: Dead of the barrows, rise!", "{0}: Мёртвые курганов, встаньте!" } }, { "elder.mark", new string[2] { "Roots stir under {1} - get out!", "Корни шевелятся под игроком {1} — выбирайтесь!" } }, { "elder.seed", new string[2] { "A seed of {0} takes root - a new nest!", "Семя ({0}) пустило корни — новое гнездо!" } }, { "bonemass.85", new string[2] { "{0}: The swamp remembers its dead! (destroy the bone pile)", "{0}: Болото помнит своих мертвецов! (разрушьте кучу костей)" } }, { "bonemass.70", new string[2] { "{0}: More bones! (piles - poison underfoot - leeches in the water)", "{0}: Больше костей! (кучи — яд под ногами — пиявки в воде)" } }, { "bonemass.55", new string[2] { "{0}: The bones shield me! (destroy all the piles)", "{0}: Кости укроют меня! (разрушьте все кучи)" } }, { "bonemass.harden", new string[2] { "{0}: the bones harden - blunt is useless, burn it!", "{0}: кости затвердели — дробящее бесполезно, жгите!" } }, { "bonemass.harden.end", new string[2] { "{0}: the bones soften again", "{0}: кости снова размякли" } }, { "bonemass.rot", new string[2] { "{0}: rotten steam - close blows sink in and poison you, strike from afar!", "{0}: гнилостный пар — удары вблизи вязнут и травят, бейте издалека!" } }, { "bonemass.rot.end", new string[2] { "{0}: the steam clears", "{0}: пар рассеялся" } }, { "bonemass.45", new string[2] { "{0} raises an abomination! Slime will crawl to the boss - kill it before it merges!", "{0} поднимает мерзость! К боссу поползёт слизь — убейте её, пока не слилась!" } }, { "bonemass.fusion", new string[2] { "{0} calls the slime - intercept it!", "{0} зовёт слизь — перехватите её!" } }, { "bonemass.40", new string[2] { "{0}: Writhans, to me!", "{0}: Скручни, ко мне!" } }, { "bonemass.35", new string[2] { "{0}: Fire of the swamp, come! (surtlings)", "{0}: Огонь болот, ко мне! (суртлинги)" } }, { "bonemass.25", new string[2] { "{0} raises the elite dead!", "{0} поднимает элитных драугров!" } }, { "bonemass.15", new string[2] { "{0}: Spirits of the swamp, feast!", "{0}: Духи болота, пируйте!" } }, { "bonemass.mark", new string[2] { "{0} spits poison under {1} - spread out!", "{0} плюёт ядом под игрока {1} — разойдитесь!" } }, { "moder.85", new string[2] { "{0}: The ice will bear my brood! (break the ice spike) - the pack is coming!", "{0}: Лёд выносит моё потомство! (разбейте ледяной сталагмит) — идёт стая!" } }, { "moder.70", new string[2] { "{0}: More ice, more young! (spikes - frost flashes under your feet)", "{0}: Больше льда — больше детёнышей! (сталагмиты — ледяные вспышки под ногами)" } }, { "moder.55", new string[2] { "{0}: The ice shields me! (break every spike)", "{0}: Лёд укроет меня! (разбейте все сталагмиты)" } }, { "moder.ice", new string[2] { "{0}: ice armor - arrows bounce off while she is on the ground, fight up close!", "{0}: ледяная броня — пока она на земле, стрелы отскакивают, бейте вблизи!" } }, { "moder.ice.end", new string[2] { "{0}: the ice armor melts", "{0}: ледяная броня тает" } }, { "moder.thorns", new string[2] { "{0}: ice thorns - every blow is paid back with frost, hit with care!", "{0}: ледяные шипы — каждый удар возвращается морозом, бейте с умом!" } }, { "moder.thorns.end", new string[2] { "{0}: the thorns break off", "{0}: шипы обламываются" } }, { "moder.45", new string[2] { "{0} calls the cultists - their fire burns her ice too!", "{0} зовёт культистов — их огонь жжёт и её лёд!" } }, { "moder.35", new string[2] { "{0} wakes the stone golem!", "{0} будит каменного голема!" } }, { "moder.20", new string[2] { "{0}: All my brood, to me!", "{0}: Всё моё потомство — ко мне!" } }, { "moder.mark", new string[2] { "{0} marks {1} - an ice blast in the red circle in a moment, step out of it!", "{0} метит игрока {1} — сейчас в красном круге ударит ледяной взрыв, выйдите из него!" } }, { "moder.breath", new string[2] { "{0} lands and chooses her victim - {1}: for 8 s she hunts only you and hits harder; the rest, keep out of her breath and strike!", "{0} садится и выбирает жертву — {1}: 8 с она охотится только на тебя и бьёт сильнее; остальные — не стойте под дыханием и бейте!" } }, { "yagluth.85", new string[2] { "{0}: My tribe, rise! (break the fuling totem)", "{0}: Моё племя, встань! (сломайте тотем фулингов)" } }, { "yagluth.70", new string[2] { "{0}: Burn! (more totems - meteors fall on the marked)", "{0}: Горите! (ещё тотемы — метеоры падают на отмеченных)" } }, { "yagluth.55", new string[2] { "{0}: The totems shield me, the shamans mend me! (break the totems, kill the shamans)", "{0}: Тотемы укроют, шаманы исцелят! (сломайте тотемы, убейте шаманов)" } }, { "yagluth.regen", new string[2] { "{0} feeds on fire - he heals unless chilled! Hit with frost!", "{0} питается огнём — он лечится, пока его не остудят! Бейте морозом!" } }, { "yagluth.regen.end", new string[2] { "{0}: the fire inside dims", "{0}: огонь внутри угасает" } }, { "yagluth.adapt", new string[2] { "{0} adapts: {1} hurts him less - switch weapons!", "{0} приспособился: урон «{1}» проходит слабее — смените оружие!" } }, { "yagluth.adapt.end", new string[2] { "{0} loses the adaptation", "{0}: приспособление прошло" } }, { "yagluth.45", new string[2] { "{0} calls the brutes!", "{0} зовёт брютов!" } }, { "yagluth.30", new string[2] { "{0} wakes the Unbjorn!", "{0} будит анбьёрна!" } }, { "yagluth.20", new string[2] { "{0}: Bones of my servants, rise!", "{0}: Кости моих слуг, встаньте!" } }, { "yagluth.15", new string[2] { "{0}: Swarm, drink their blood!", "{0}: Рой, пей их кровь!" } }, { "yagluth.10", new string[2] { "{0} calls an echo of the dragon queen!", "{0} призывает эхо королевы драконов!" } }, { "yagluth.mark", new string[2] { "{0} calls meteors on {1} - run!", "{0} зовёт метеоры на игрока {1} — бегите!" } }, { "yagluth.roar", new string[2] { "{0} draws breath for a roar - get farther than {1} m from him or raise your shield!", "{0} набирает воздух для рёва — отойдите дальше {1} м или поднимите щит!" } }, { "yagluth.beam", new string[2] { "{0} has chosen his victim - {1}: for 8 s he hunts only you and hits harder; the rest, strike while he is busy!", "{0} выбрал жертву — {1}: 8 с он охотится только на тебя и бьёт сильнее; остальные — бейте, пока он занят!" } }, { "queen.85", new string[2] { "{0} lays a clutch! (smash the eggs before they hatch)", "{0} откладывает кладку! (разбейте яйца, пока не вылупились)" } }, { "queen.70", new string[2] { "{0}: More children! (eggs - acid falls on the marked)", "{0}: Больше детей! (яйца — кислота на отмеченных)" } }, { "queen.55", new string[2] { "{0}: My brood shields me! (smash every egg)", "{0}: Выводок укроет меня! (разбейте все яйца)" } }, { "queen.blood", new string[2] { "{0} thirsts - her blows heal her! Dodge, block, keep away!", "{0} жаждет крови — её удары лечат её! Уклоняйтесь, блокируйте, не подставляйтесь!" } }, { "queen.blood.end", new string[2] { "{0}: the thirst fades", "{0}: жажда утихает" } }, { "queen.acid", new string[2] { "{0}: acid thorns - every blow is paid back with poison, hit with care!", "{0}: кислотные шипы — каждый удар возвращается ядом, бейте с умом!" } }, { "queen.acid.end", new string[2] { "{0}: the acid dries up", "{0}: кислота высыхает" } }, { "queen.45", new string[2] { "{0} calls her guards!", "{0} зовёт стражей!" } }, { "queen.30", new string[2] { "{0} calls a gjall from the mist!", "{0} призывает гьялля из тумана!" } }, { "queen.20", new string[2] { "{0}: All my brood, devour them!", "{0}: Весь выводок — пожрите их!" } }, { "queen.mark", new string[2] { "{0} spits acid at {1} - spread out!", "{0} плюёт кислотой в игрока {1} — разойдитесь!" } }, { "queen.cocoon", new string[2] { "{0} hides behind her guards - kill them to reach her!", "{0} укрылась за стражами — убейте их, чтобы добраться до неё!" } }, { "fader.85", new string[2] { "{0}: Rise, charred! (break the spawner stone)", "{0}: Встаньте, обугленные! (разбейте камень-спавнер)" } }, { "fader.70", new string[2] { "{0} calls a fallen valkyrie! (and another stone)", "{0} призывает падшую валькирию! (и ещё камень)" } }, { "fader.55", new string[2] { "{0}: The stones shield me! (break them all)", "{0}: Камни укроют меня! (разбейте их все)" } }, { "fader.molten", new string[2] { "{0}: molten armor - it cracks under blows from afar and burns those close, strike from range!", "{0}: раскалённая броня — трескается от ударов издалека и обжигает тех, кто рядом, бейте издалека!" } }, { "fader.molten.end", new string[2] { "{0}: the armor cools", "{0}: броня остывает" } }, { "fader.ash", new string[2] { "{0}: ash veil - he is blind in the ash, strike up close!", "{0}: пепельная завеса — он слеп в пепле, бейте вблизи!" } }, { "fader.ash.end", new string[2] { "{0}: the ash settles", "{0}: пепел оседает" } }, { "fader.45", new string[2] { "{0} wakes a morgen!", "{0} будит моргена!" } }, { "fader.30", new string[2] { "{0} calls Lord Reto!", "{0} призывает лорда Рето!" } }, { "window", new string[2] { "{0}: the shield has fallen - strike now!", "{0}: защита пала — бейте!" } }, { "shield.fade", new string[2] { "{0}: the shield crumbles by itself", "{0}: щит рассыпается сам" } }, { "shield.left", new string[2] { "{0}: the shield holds - {1} left to break!", "{0}: щит держится — осталось разбить: {1}!" } }, { "status.shield", new string[2] { "Shield - left to break: {0}", "Щит — осталось разбить: {0}" } }, { "status.targets", new string[2] { "Break the glowing ones: {0}", "Разбейте подсвеченные: {0}" } }, { "status.window", new string[2] { "Burn window - strike! {0} s", "Окно уязвимости — бейте! {0} с" } }, { "status.cycle", new string[2] { "{0} ({1} s)", "{0} ({1} с)" } }, { "pin.target", new string[2] { "break", "разбить" } }, { "reset", new string[2] { "{0} regains strength...", "{0} восстанавливает силы…" } }, { "cmd.help", new string[2] { "eb status | check | phase <n> | reset | clear | probe <prefab> | players <n|0>", "eb status | check | phase <n> | reset | clear | probe <префаб> | players <n|0>" } }, { "cmd.noboss", new string[2] { "No boss owned by this client nearby (the mechanics run on the owner).", "Рядом нет босса, которым владеет этот клиент (механики работают у владельца)." } }, { "cmd.reset", new string[2] { "{0}: fight reset.", "{0}: бой сброшен." } }, { "cmd.clear", new string[2] { "Killed {0} monster(s) within 60 m (bosses, players and tamed ones spared).", "Убито монстров в радиусе 60 м: {0} (боссы, игроки и прирученные не тронуты)." } }, { "cmd.phase", new string[2] { "{0}: phase {1} ({2}%) forced.", "{0}: фаза {1} ({2} %) запущена." } }, { "cmd.phaseusage", new string[2] { "eb phase <0..{0}>", "eb phase <0..{0}>" } }, { "cmd.players", new string[2] { "eb players <n> (0 = count real players)", "eb players <n> (0 — считать реальных игроков)" } }, { "cmd.playerscount", new string[2] { "Group size: counted.", "Размер группы: считается по игрокам." } }, { "cmd.playersforced", new string[2] { "Group size forced to {0} (this client only).", "Размер группы принудительно {0} (только на этом клиенте)." } }, { "cmd.inert", new string[2] { "{0} is inert after errors (see the log).", "{0} отключился после ошибок (см. лог)." } }, { "cmd.noworld", new string[2] { "Not in a world.", "Не в мире." } }, { "cmd.nobosses", new string[2] { "No known boss loaded nearby.", "Рядом нет загруженных боссов мода." } }, { "cmd.status", new string[2] { "{0}: {1}/{2}, HP {3}%, phases {4}/{5}, {6}, group {7}, damage x{8}, adds {9}, nests {10}{11}", "{0}: {1}/{2}, HP {3} %, фазы {4}/{5}, {6}, группа {7}, урон x{8}, адды {9}, гнёзда {10}{11}" } }, { "cmd.ownedhere", new string[2] { "owned here", "владелец — этот клиент" } }, { "cmd.ownedother", new string[2] { "owned by another client", "владелец — другой клиент" } }, { "cmd.shield", new string[2] { ", SHIELD", ", ЩИТ" } }, { "cmd.window", new string[2] { ", WINDOW", ", ОКНО" } }, { "cmd.cocoon", new string[2] { ", COCOON", ", КОКОН" } }, { "cmd.fixate", new string[2] { ", FIXATED", ", ФИКСАЦИЯ" } }, { "cmd.resist", new string[2] { ", RESIST", ", СОПРОТИВЛЕНИЕ" } }, { "cmd.cycle.sap", new string[2] { ", BARK (sap)", ", КОРА (сок)" } }, { "cmd.cycle.back", new string[2] { ", BARK (back)", ", КОРА (спина)" } }, { "cmd.cycle.harden", new string[2] { ", HARDENED", ", ЗАТВЕРДЕЛ" } }, { "cmd.cycle.rot", new string[2] { ", ROTTEN STEAM", ", ГНИЛОСТНЫЙ ПАР" } }, { "cmd.cycle.icearmor", new string[2] { ", ICE ARMOR", ", ЛЕДЯНАЯ БРОНЯ" } }, { "cmd.cycle.thorns", new string[2] { ", ICE THORNS", ", ЛЕДЯНЫЕ ШИПЫ" } }, { "cmd.cycle.regen", new string[2] { ", REGENERATION", ", РЕГЕНЕРАЦИЯ" } }, { "cmd.cycle.adapt", new string[2] { ", ADAPTED", ", АДАПТАЦИЯ" } }, { "cmd.cycle.bloodthirst", new string[2] { ", BLOODTHIRST", ", КРОВОЖАДНОСТЬ" } }, { "cmd.cycle.acidthorns", new string[2] { ", ACID THORNS", ", КИСЛОТНЫЕ ШИПЫ" } }, { "cmd.cycle.molten", new string[2] { ", MOLTEN ARMOR", ", РАСКАЛЁННАЯ БРОНЯ" } }, { "cmd.cycle.ashveil", new string[2] { ", ASH VEIL", ", ПЕПЕЛЬНАЯ ЗАВЕСА" } }, { "cmd.checkdone", new string[2] { "Self-check: {0} prefab(s) OK, {1} problem(s) - details in the log.", "Самопроверка: {0} префаб(ов) в порядке, проблем: {1} — подробности в логе." } } }; private ConfigEntry<string> _cfgGuestLanguage; private readonly HashSet<long> _moddedPeers = new HashSet<long>(); private bool _helloSent; private readonly List<string> _centerLines = new List<string>(); private string _centerShown; private float _centerAt; private ConfigEntry<bool> _cfgSync; private bool _syncDirty; private bool _serverSynced; private readonly Dictionary<string, object> _serverByKey = new Dictionary<string, object>(); private static MethodInfo _miSetTarget; private readonly List<ZDOID> _tmpThreatIds = new List<ZDOID>(); internal bool Active { get { if (!_disabledByErrors && Sb(_cfgEnabled) && (Object)(object)ZNet.instance != (Object)null) { return (Object)(object)ZNetScene.instance != (Object)null; } return false; } } internal BossDef BossOf(ZDO zdo) { if (zdo == null || !_bossByHash.TryGetValue(zdo.GetPrefab(), out var value)) { return null; } return value; } private void AddBoss(BossDef b) { b.Hash = StringExtensionMethods.GetStableHashCode(b.Prefab); _bosses.Add(b); _bossByHash[b.Hash] = b; } private void BuildBosses() { AddBoss(Eikthyr()); AddBoss(Elder()); AddBoss(Bonemass()); AddBoss(Moder()); AddBoss(Yagluth()); AddBoss(Queen()); AddBoss(Fader()); } private static PhaseDef Phase(BossDef b, float pct, string say) { PhaseDef phaseDef = new PhaseDef(); phaseDef.Pct = pct; phaseDef.Say = say; PhaseDef phaseDef2 = phaseDef; b.Phases.Add(phaseDef2); return phaseDef2; } private static Dictionary<DamageType, float> Mods(params object[] pairs) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) Dictionary<DamageType, float> dictionary = new Dictionary<DamageType, float>(); for (int i = 0; i + 1 < pairs.Length; i += 2) { dictionary[(DamageType)pairs[i]] = (float)pairs[i + 1]; } return dictionary; } private void BindCycle(BossDef d, string prefix, string whatEn, string whatRu, params string[] variantIds) { if (variantIds != null && variantIds.Length > 1) { List<string> list = new List<string>(); list.Add("Random"); list.AddRange(variantIds); list.Add("Auto"); d.CfgCycleVariant = S(d.Section, prefix + "Variant", "Random", "Which variant (" + whatEn + ") comes: Random (chosen anew each time), a variant name to pin it, or Auto (positional variant for a group of 3+). A single player never gets a positional variant.", "Какой вариант (" + whatRu + "): Random — заново каждый раз, имя варианта — всегда он, Auto — позиционный для группы от 3 игроков. Одному игроку позиционный вариант не выпадает никогда.", list.ToArray()); } d.CfgCycleDuration = F(d.Section, prefix + "Duration", 30f, 5f, 120f, "Seconds each " + whatEn + " lasts.", "Длительность (" + whatRu + "), секунд."); d.CfgCycleCdMin = F(d.Section, prefix + "CooldownMin", d.CycleCdMinDefault, 5f, 300f, "Cooldown between: from...", "Перерыв между: от…"); d.CfgCycleCdMax = F(d.Section, prefix + "CooldownMax", d.CycleCdMaxDefault, 5f, 300f, "...to (random each time).", "…до (случайно каждый раз)."); d.CfgCycleDelay = F(d.Section, prefix + "StartDelay", 60f, 0f, 300f, "The first one comes when the stagger after the fallen shield ends; if the shield still stands this long after 55%, it starts anyway.", "Первый раз — когда кончается оглушение после падения щита; если щит стоит дольше этого после 55 %, начинается всё равно."); } private static BossDef Eikthyr() { //IL_019b: Unknown result type (might be due to invalid IL or missing references) BossDef bossDef = new BossDef(); bossDef.Prefab = "Eikthyr"; bossDef.Section = "10 Eikthyr"; BossDef bossDef2 = bossDef; Phase(bossDef2, 80f, "eikthyr.80").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[2] { "Boar", "Neck" }, Count = 2f }); Phase(bossDef2, 60f, "eikthyr.60").Acts.Add(new Act { Kind = ActKind.Charge }); Phase(bossDef2, 50f, "eikthyr.50").Acts.Add(new Act { Kind = ActKind.Totem, Prop = "skull_pile", Count = 1f, NoDrop = true, Prefabs = new string[3] { "Skeleton_Meadows_noarcher", "Skeleton_Meadows_noarcher", "Skeleton_Meadows" }, Interval = 12f, MaxAlive = 3 }); Phase(bossDef2, 30f, "eikthyr.30").Acts.Add(new Act { Kind = ActKind.Marks, Prefabs = new string[1] { "lightningAOE" }, Prop = "vfx_prespawn", MarkKey = "eikthyr.mark", Count = 1f, Damage = 15f, DamageType = (DamageType)128 }); Phase(bossDef2, 15f, "eikthyr.15").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Boar" }, Level = 3, HpMul = 3f }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 120, 180, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Amber", 3, 3, perPlayer: true)); bossDef2.Reward.NextBiome.Add(Loot.Stack("CopperOre", 0.5f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("TinOre", 0.5f)); bossDef2.Reward.Gear = new string[10] { "AxeFlint", "SpearFlint", "KnifeFlint", "Club", "Bow", "ShieldWood", "ArmorLeatherChest", "ArmorLeatherLegs", "HelmetLeather", "CapeDeerHide" }; bossDef2.Reward.NextGear = new string[9] { "AxeBronze", "MaceBronze", "SwordBronze", "SpearBronze", "AtgeirBronze", "ArmorBronzeChest", "ArmorBronzeLegs", "HelmetBronze", "ShieldBronzeBuckler" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgTotemPrefab = pl.S(d.Section, "TotemPrefab", "skull_pile", "Destructible vanilla object used as the skeleton totem at 50%. Must be networked and destructible (see the self-check in the log). Fallback: BonePileSpawner.", "Разрушаемый ванильный объект — тотем со скелетами на 50 %. Должен быть сетевым и разрушаемым (см. самопроверку в логе). Запасной — BonePileSpawner."); d.CfgMarkPrefab = pl.S(d.Section, "MarkPrefab", "lightningAOE", "Vanilla AoE prefab of the lightning strike at 30%.", "Ванильный AoE-префаб удара молнии на 30 %."); d.CfgMarkEffect = pl.S(d.Section, "MarkEffect", "vfx_prespawn", "Vanilla effect on the marked player before the strike (players with the mod).", "Ванильный эффект на отмеченном игроке до удара (у игроков с модом)."); d.CfgMarkDamage = pl.F(d.Section, "MarkDamage", 15f, 0f, 500f, "Lightning damage of the strike (before 04 Marks DamageMultiplier).", "Урон молнией (до множителя из 04 Marks)."); d.CfgChargeInterval = pl.F(d.Section, "ChargeInterval", 20f, 5f, 120f, "Seconds between charges from 60%.", "Секунд между рывками с 60 %."); d.CfgChargeSpeed = pl.F(d.Section, "ChargeSpeed", 2f, 1f, 4f, "Speed multiplier during a charge.", "Множитель скорости во время рывка."); d.CfgChargeDuration = pl.F(d.Section, "ChargeDuration", 2.5f, 0.5f, 8f, "Seconds a charge lasts.", "Длительность рывка, секунд."); }; return bossDef2; } private static BossDef Elder() { BossDef bossDef = new BossDef(); bossDef.Prefab = "gd_king"; bossDef.Section = "11 Elder"; BossDef bossDef2 = bossDef; Phase(bossDef2, 85f, "elder.85").Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_GreydwarfNest" }, Count = 1f }); PhaseDef phaseDef = Phase(bossDef2, 70f, "elder.70"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_GreydwarfNest" }, Count = 2f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Marks, Creature = "TentaRoot", CreatureCount = 4, RingRadius = 3f, Lifetime = 15f, Prop = "vfx_prespawn", MarkKey = "elder.mark", Count = 1f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Seeds, Prefabs = new string[1] { "Spawner_GreydwarfNest" }, Chance = 0.05f, Interval = 20f, MaxAlive = 2, MarkKey = "elder.seed" }); phaseDef = Phase(bossDef2, 55f, "elder.55"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_GreydwarfNest" }, Count = 3f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Shield }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cycle, Duration = 30f, CooldownMin = 50f, CooldownMax = 70f, Delay = 60f, EndKey = "elder.bark.end", Variants = new List<CycleVariant> { new CycleVariant { Id = "Sap", Say = "elder.bark.sap", Other = 0.25f, Mods = Mods((object)(DamageType)2, 1.25f, (object)(DamageType)32, 0.25f) }, new CycleVariant { Id = "Back", Say = "elder.bark.back", Other = 0.25f, Back = true } } }); Phase(bossDef2, 45f, "elder.45").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Troll" }, ExtraFrom = 3 }); Phase(bossDef2, 30f, "elder.30").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Bjorn" } }); phaseDef = Phase(bossDef2, 20f, "elder.20"); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Greydwarf_Elite" }, Count = 2f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Greydwarf_Shaman" }, Count = 1f, Role = 1 }); Phase(bossDef2, 10f, "elder.10").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[2] { "Skeleton", "Ghost" }, Count = 1f }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 240, 360, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Amber", 3, 6, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Ruby", 1, 1, perPlayer: false)); bossDef2.Reward.Valuables.Add(Loot.Stack("CopperOre", 1f)); bossDef2.Reward.Valuables.Add(Loot.Stack("TinOre", 1f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("IronScrap", 0.5f)); bossDef2.Reward.Gear = new string[15] { "AxeBronze", "MaceBronze", "SwordBronze", "SpearBronze", "AtgeirBronze", "KnifeCopper", "BowFineWood", "ArmorBronzeChest", "ArmorBronzeLegs", "HelmetBronze", "ShieldBronzeBuckler", "ArmorTrollLeatherChest", "ArmorTrollLeatherLegs", "HelmetTrollLeather", "CapeTrollHide" }; bossDef2.Reward.NextGear = new string[9] { "SwordIron", "MaceIron", "AxeIron", "SpearElderbark", "AtgeirIron", "ArmorIronChest", "ArmorIronLegs", "HelmetIron", "ShieldBanded" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgNestPrefab = pl.S(d.Section, "NestPrefab", "Spawner_GreydwarfNest", "Vanilla destructible spawner placed at 85/70/55%.", "Ванильный разрушаемый спавнер на 85/70/55 %."); d.CfgMarkCreature = pl.S(d.Section, "RootsCreature", "TentaRoot", "Creature summoned in a ring around the marked player from 70%.", "Существо, которое появляется кольцом вокруг отмеченного игрока с 70 %."); d.CfgMarkEffect = pl.S(d.Section, "MarkEffect", "vfx_prespawn", "Vanilla effect on the marked player before the roots (players with the mod).", "Ванильный эффект на отмеченном игроке до корней (у игроков с модом)."); pl.BindCycle(d, "Bark", "living bark - Sap: fire x0.25, slash x1.25, the rest x0.25; Back: x0.25 from the front, full from behind", "живая кора: Sap — огонь ×0.25, рубящий ×1.25, остальное ×0.25; Back — спереди ×0.25, в спину полный", "Sap", "Back"); d.CfgBackArc = pl.F(d.Section, "BackArc", 120f, 30f, 270f, "Back variant: width of the arc behind the Elder that counts as 'the back', degrees.", "Вариант Back: ширина дуги позади Древнего, которая считается спиной, градусов."); d.CfgHealPercent = pl.F(d.Section, "HealerPercentPerSecond", 0.5f, 0f, 10f, "Each living shaman near the Elder heals it this % of max HP per second (at most 2 count). Overrides 09 Raid / HealPercentPerSecond for the Elder.", "Каждый живой шаман рядом с Древним лечит его на столько % макс. HP в секунду (учитываются не больше 2). Для Древнего заменяет 09 Raid / HealPercentPerSecond."); }; return bossDef2; } private static BossDef Bonemass() { //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) BossDef bossDef = new BossDef(); bossDef.Prefab = "Bonemass"; bossDef.Section = "12 Bonemass"; BossDef bossDef2 = bossDef; Phase(bossDef2, 85f, "bonemass.85").Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_DraugrPile" }, Count = 1f }); PhaseDef phaseDef = Phase(bossDef2, 70f, "bonemass.70"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_DraugrPile" }, Count = 2f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Leech" }, Count = 2f, InWater = true }); phaseDef.Acts.Add(new Act { Kind = ActKind.Marks, Prefabs = new string[1] { "bonemass_aoe" }, Prop = "vfx_prespawn", MarkKey = "bonemass.mark", Count = 1f, Damage = 25f, DamageType = (DamageType)256 }); phaseDef.Acts.Add(new Act { Kind = ActKind.HitEffect, Effect = "Wet" }); phaseDef = Phase(bossDef2, 55f, "bonemass.55"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_DraugrPile" }, Count = 3f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Shield }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cycle, Duration = 30f, CooldownMin = 50f, CooldownMax = 70f, Delay = 60f, Variants = new List<CycleVariant> { new CycleVariant { Id = "Harden", Say = "bonemass.harden", EndKey = "bonemass.harden.end", Other = 1f, Mods = Mods((object)(DamageType)1, 0.25f, (object)(DamageType)32, 2f) }, new CycleVariant { Id = "Rot", Say = "bonemass.rot", EndKey = "bonemass.rot.end", Other = 1f, MeleeFactor = 0.5f, MeleeRange = 5f, Retaliate = 12f, RetaliateType = (DamageType)256 } } }); phaseDef = Phase(bossDef2, 45f, "bonemass.45"); phaseDef.Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Abomination" } }); phaseDef.Acts.Add(new Act { Kind = ActKind.Fusion, Prefabs = new string[3] { "Blob", "Blob", "BlobElite" }, Count = 1f, Interval = 45f, Heal = 6f, MarkKey = "bonemass.fusion" }); Phase(bossDef2, 40f, "bonemass.40").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Writhan" }, Count = 1f }); phaseDef = Phase(bossDef2, 35f, "bonemass.35"); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Surtling" }, Count = 2f }); phaseDef.Acts.Add(new Act { Kind = ActKind.HitEffect, Effect = "Tared" }); Phase(bossDef2, 25f, "bonemass.25").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Draugr_Elite" }, Count = 1f }); Phase(bossDef2, 15f, "bonemass.15").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[3] { "Wraith", "Bat_Swamp", "Bat_Swamp" }, Count = 1f }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 360, 540, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Ruby", 1, 2, perPlayer: false)); bossDef2.Reward.Valuables.Add(new Loot("AmberPearl", 1, 1, perPlayer: true)); bossDef2.Reward.Valuables.Add(Loot.Stack("IronScrap", 1f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("SilverOre", 0.5f)); bossDef2.Reward.Gear = new string[14] { "SwordIron", "MaceIron", "AxeIron", "AtgeirIron", "SpearElderbark", "BowHuntsman", "ArmorIronChest", "ArmorIronLegs", "HelmetIron", "ShieldBanded", "ShieldIronTower", "ArmorRootChest", "ArmorRootLegs", "HelmetRoot" }; bossDef2.Reward.NextGear = new string[10] { "SwordSilver", "MaceSilver", "SpearWolfFang", "KnifeSilver", "BowDraugrFang", "ArmorWolfChest", "ArmorWolfLegs", "HelmetDrake", "CapeWolf", "ShieldSilver" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgNestPrefab = pl.S(d.Section, "NestPrefab", "Spawner_DraugrPile", "Vanilla destructible spawner placed at 85/70/55% (bone pile). Alternative: BonePileSpawner_swamp.", "Ванильный разрушаемый спавнер на 85/70/55 % (куча костей). Альтернатива — BonePileSpawner_swamp."); d.CfgMarkPrefab = pl.S(d.Section, "MarkPrefab", "bonemass_aoe", "Vanilla AoE prefab of the poison puddle under a marked player from 70%.", "Ванильный AoE-префаб ядовитой лужи под отмеченным игроком с 70 %."); d.CfgMarkEffect = pl.S(d.Section, "MarkEffect", "vfx_prespawn", "Vanilla effect on the marked player before the puddle (players with the mod).", "Ванильный эффект на отмеченном игроке до лужи (у игроков с модом)."); d.CfgMarkDamage = pl.F(d.Section, "MarkDamage", 25f, 0f, 500f, "Poison damage of the puddle (before 04 Marks DamageMultiplier).", "Урон ядом лужи (до множителя из 04 Marks)."); pl.BindCycle(d, "Cycle", "Harden: blunt x0.25, fire x2; Rot: close hits x0.5 and poison the attacker, ranged full", "Harden — затвердевание: дробящий ×0.25, огонь ×2; Rot — гнилостный пар: удары вблизи ×0.5 и травят атакующего, издалека полный", "Harden", "Rot"); d.CfgCycleMelee = pl.F(d.Section, "RotMeleeFactor", 0.5f, 0f, 1f, "Rotten steam: damage of hits from within 5 m (x).", "Гнилостный пар: урон ударов ближе 5 м (×)."); d.CfgCycleRetaliate = pl.F(d.Section, "RotPoisonDamage", 12f, 0f, 200f, "Rotten steam: poison dealt back to a close attacker per hit (at most once a second per player).", "Гнилостный пар: яд, который получает атакующий вблизи за удар (не чаще раза в секунду на игрока)."); d.CfgFusionInterval = pl.F(d.Section, "SlimeInterval", 45f, 5f, 180f, "From 45%: seconds between slime waves crawling to Bonemass.", "С 45 %: секунд между волнами слизи, ползущей к Массивному."); d.CfgFusionHeal = pl.F(d.Section, "SlimeWaveHealPercent", 6f, 0f, 50f, "% of max HP one slime wave can heal Bonemass in total, shared among its slimes (a bigger wave does not heal more).", "Сколько % макс. HP может вылечить Массивному одна волна слизи в сумме, поровну на её капли (большая волна не лечит больше)."); }; return bossDef2; } private static BossDef Moder() { //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) BossDef bossDef = new BossDef(); bossDef.Prefab = "Dragon"; bossDef.Section = "13 Moder"; BossDef bossDef2 = bossDef; bossDef2.CycleCdMinDefault = 40f; bossDef2.CycleCdMaxDefault = 55f; string[] prefabs = new string[1] { "Hatchling" }; bossDef2.FlyerPrefab = "Hatchling"; PhaseDef phaseDef = Phase(bossDef2, 85f, "moder.85"); phaseDef.Acts.Add(new Act { Kind = ActKind.Totem, Prop = "caverock_ice_stalagmite", Count = 1f, Prefabs = prefabs, Interval = 15f, MaxAlive = 2, ExtraAliveFrom = 0, AlivePerPlayer = 2, Fallback = null }); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Wolf" }, NightPrefabs = new string[1] { "Ulv" }, Count = 2f }); phaseDef = Phase(bossDef2, 70f, "moder.70"); phaseDef.Acts.Add(new Act { Kind = ActKind.Totem, Prop = "caverock_ice_stalagmite", Count = 2f, Prefabs = prefabs, Interval = 15f, MaxAlive = 2, ExtraAliveFrom = 0, AlivePerPlayer = 2, Fallback = null }); phaseDef.Acts.Add(new Act { Kind = ActKind.Marks, Prefabs = new string[1] { "FenringIceNova_aoe" }, Prop = "vfx_prespawn", MarkKey = "moder.mark", StrikeFx = "fx_DvergerMage_Nova_ring", MarkRange = 40f, Count = 1f, Damage = 25f, DamageType = (DamageType)64 }); phaseDef = Phase(bossDef2, 55f, "moder.55"); phaseDef.Acts.Add(new Act { Kind = ActKind.Totem, Prop = "caverock_ice_stalagmite", Count = 3f, Prefabs = prefabs, Interval = 15f, MaxAlive = 2, ExtraAliveFrom = 0, AlivePerPlayer = 2, Fallback = null }); phaseDef.Acts.Add(new Act { Kind = ActKind.Shield }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cycle, Duration = 30f, CooldownMin = 40f, CooldownMax = 55f, Delay = 60f, Variants = new List<CycleVariant> { new CycleVariant { Id = "IceArmor", Say = "moder.ice", EndKey = "moder.ice.end", Other = 1f, MeleeRange = 6f, RangedFactor = 0.25f, GroundedOnly = true }, new CycleVariant { Id = "Thorns", Say = "moder.thorns", EndKey = "moder.thorns.end", Other = 1f, ThornsPercent = 12f, ThornsMin = 5f, RetaliateType = (DamageType)64 } } }); phaseDef = Phase(bossDef2, 45f, "moder.45"); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Fenring_Cultist" }, Count = 1f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Fixate, Land = true, Interval = 25f, Duration = 8f, MarkKey = "moder.breath" }); Phase(bossDef2, 35f, "moder.35").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "StoneGolem" } }); phaseDef = Phase(bossDef2, 20f, "moder.20"); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Fenring" }, Count = 1f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = prefabs, Count = 1f }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 480, 720, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Ruby", 1, 2, perPlayer: false)); bossDef2.Reward.Valuables.Add(new Loot("SilverNecklace", 1, 1, perPlayer: true)); bossDef2.Reward.Valuables.Add(Loot.Stack("SilverOre", 1f)); bossDef2.Reward.Valuables.Add(Loot.Stack("Obsidian", 1f)); bossDef2.Reward.Valuables.Add(Loot.Stack("Crystal", 1f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("BlackMetalScrap", 0.5f)); bossDef2.Reward.Gear = new string[13] { "SwordSilver", "MaceSilver", "SpearWolfFang", "KnifeSilver", "BowDraugrFang", "ShieldSilver", "ArmorWolfChest", "ArmorWolfLegs", "HelmetDrake", "CapeWolf", "ArmorFenringChest", "ArmorFenringLegs", "HelmetFenring" }; bossDef2.Reward.NextGear = new string[10] { "SwordBlackmetal", "AxeBlackMetal", "AtgeirBlackmetal", "KnifeBlackMetal", "MaceNeedle", "ShieldBlackmetal", "ArmorPaddedCuirass", "ArmorPaddedGreaves", "HelmetPadded", "CapeLinen" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgTotemPrefab = pl.S(d.Section, "TotemPrefab", "caverock_ice_stalagmite", "Destructible vanilla object that hatches drakes at 85/70/55% and holds the shield. Must be networked and destructible (see the self-check).", "Разрушаемый ванильный объект, из которого вылупляются дрейки на 85/70/55 % и который держит щит. Должен быть сетевым и разрушаемым (см. самопроверку)."); d.CfgMarkPrefab = pl.S(d.Section, "MarkPrefab", "FenringIceNova_aoe", "Vanilla AoE prefab of the ice flash under a marked player from 70%.", "Ванильный AoE-префаб ледяной вспышки под отмеченным игроком с 70 %."); d.CfgMarkEffect = pl.S(d.Section, "MarkEffect", "vfx_prespawn", "Vanilla effect on the marked player before the flash (players with the mod).", "Ванильный эффект на отмеченном игроке до вспышки (у игроков с модом)."); d.CfgMarkInterval = pl.F(d.Section, "MarkInterval", 15f, 5f, 120f, "Seconds between her ice flashes (x0.75 in Hard). Overrides 04 Marks / Interval for Moder.", "Секунд между её ледяными вспышками (×0.75 в Hard). Для Модер заменяет 04 Marks / Interval."); d.CfgFlyerInterval = pl.F(d.Section, "DrakeFlightInterval", 30f, 5f, 300f, "All fight long, every this many seconds 1-2 drakes fly in (x0.75 in Hard); not counted with the stalagmites' drakes.", "Весь бой раз в столько секунд прилетают 1–2 дрейка (×0.75 в Hard); считаются отдельно от дрейков сталагмитов."); d.CfgFlyerMax = pl.I(d.Section, "DrakeFlightMax", 2, 0, 10, "At most this many of the flying-in drakes alive at once (0 = off).", "Не больше стольких прилетевших дрейков одновременно (0 = выкл.)."); d.CfgMarkDamage = pl.F(d.Section, "MarkDamage", 25f, 0f, 500f, "Frost damage of the flash (before 04 Marks DamageMultiplier); frost also slows.", "Урон морозом вспышки (до множителя из 04 Marks); мороз ещё и замедляет."); pl.BindCycle(d, "Cycle", "IceArmor: hits from afar x0.25 while she is on the ground; Thorns: every hit is paid back with frost", "IceArmor — ледяная броня: удары издалека ×0.25, пока она на земле; Thorns — ледяные шипы: каждый удар возвращается морозом", "IceArmor", "Thorns"); d.CfgCycleRanged = pl.F(d.Section, "IceArmorRangedFactor", 0.25f, 0f, 1f, "Ice armor: damage of hits from farther than 6 m (x), only while Moder is on the ground.", "Ледяная броня: урон ударов дальше 6 м (×), только пока Модер на земле."); d.CfgCycleThorns = pl.F(d.Section, "ThornsPercent", 12f, 0f, 100f, "Ice thorns: % of each hit's damage dealt back as frost to the attacker (at least 5, at most once a second per player).", "Ледяные шипы: % урона удара, который возвращается атакующему морозом (не меньше 5, не чаще раза в секунду на игрока)."); }; return bossDef2; } private static BossDef Yagluth() { //IL_035d: Unknown result type (might be due to invalid IL or missing references) BossDef bossDef = new BossDef(); bossDef.Prefab = "GoblinKing"; bossDef.Section = "14 Yagluth"; BossDef bossDef2 = bossDef; string[] prefabs = new string[3] { "Goblin", "Goblin", "GoblinArcher" }; Phase(bossDef2, 85f, "yagluth.85").Acts.Add(new Act { Kind = ActKind.Totem, Prop = "goblin_totempole", Count = 1f, Prefabs = prefabs, Interval = 12f, MaxAlive = 3, AlivePerPlayer = 2, NoDrop = true, Fallback = null }); PhaseDef phaseDef = Phase(bossDef2, 70f, "yagluth.70"); phaseDef.Acts.Add(new Act { Kind = ActKind.Totem, Prop = "goblin_totempole", Count = 2f, Prefabs = prefabs, Interval = 12f, MaxAlive = 3, AlivePerPlayer = 2, NoDrop = true, Fallback = null }); phaseDef.Acts.Add(new Act { Kind = ActKind.Marks, Prefabs = new string[1] { "spawn_meteors" }, Prop = "vfx_prespawn", MarkKey = "yagluth.mark", MarkRange = 40f, Count = 1f }); phaseDef = Phase(bossDef2, 55f, "yagluth.55"); phaseDef.Acts.Add(new Act { Kind = ActKind.Totem, Prop = "goblin_totempole", Count = 3f, Prefabs = prefabs, Interval = 12f, MaxAlive = 3, AlivePerPlayer = 2, NoDrop = true, Fallback = null }); phaseDef.Acts.Add(new Act { Kind = ActKind.Roar, Interval = 45f, Radius = 30f, Damage = 30f, Effect = "Tared", MarkKey = "yagluth.roar" }); phaseDef.Acts.Add(new Act { Kind = ActKind.Shield }); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "GoblinShaman" }, Count = 1f, Role = 1 }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cycle, Duration = 30f, CooldownMin = 50f, CooldownMax = 70f, Delay = 60f, Variants = new List<CycleVariant> { new CycleVariant { Id = "Regen", Say = "yagluth.regen", EndKey = "yagluth.regen.end", RegenPercent = 0.3f, RegenStopType = (DamageType)64, RegenStopSeconds = 3f }, new CycleVariant { Id = "Adapt", Say = "yagluth.adapt", EndKey = "yagluth.adapt.end", Adapt = true, AdaptFactor = 0.6f, AdaptOthers = 1.1f } } }); phaseDef = Phase(bossDef2, 45f, "yagluth.45"); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "GoblinBrute" }, Count = 1f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Fixate, Interval = 30f, Duration = 8f, MarkKey = "yagluth.beam" }); phaseDef.Acts.Add(new Act { Kind = ActKind.HitEffect, Effect = "Tared" }); Phase(bossDef2, 30f, "yagluth.30").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Unbjorn" } }); Phase(bossDef2, 20f, "yagluth.20").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[3] { "Skeleton_NoArcher", "Skeleton", "Skeleton_Poison" }, Count = 1f }); Phase(bossDef2, 15f, "yagluth.15").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Deathsquito" }, Count = 1f }); Phase(bossDef2, 10f, "yagluth.10").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Aspect_Moder" }, HpMul = 0.5f, Gate = "EchoOfModer" }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 600, 900, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("SilverNecklace", 1, 2, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Ruby", 2, 3, perPlayer: false)); bossDef2.Reward.Valuables.Add(Loot.Stack("BlackMetalScrap", 1f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("Softtissue", 0.5f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("BlackCore", 0.5f)); bossDef2.Reward.Gear = new string[12] { "SwordBlackmetal", "AxeBlackMetal", "AtgeirBlackmetal", "KnifeBlackMetal", "MaceNeedle", "ShieldBlackmetal", "ShieldBlackmetalTower", "ArmorPaddedCuirass", "ArmorPaddedGreaves", "HelmetPadded", "CapeLinen", "CapeLox" }; bossDef2.Reward.NextGear = new string[18] { "SwordMistwalker", "AxeJotunBane", "THSwordKrom", "KnifeSkollAndHati", "SpearCarapace", "AtgeirHimminAfl", "MaceEldner", "BowSpineSnap", "CrossbowArbalest", "ShieldCarapace", "ArmorCarapaceChest", "ArmorCarapaceLegs", "HelmetCarapace", "ArmorMageChest", "ArmorMageLegs", "HelmetMage", "StaffFireball", "StaffIceShards" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgTotemPrefab = pl.S(d.Section, "TotemPrefab", "goblin_totempole", "Destructible vanilla object that spawns fulings at 85/70/55% and holds the shield. Must be networked and destructible (see the self-check).", "Разрушаемый ванильный объект, из которого идут фулинги на 85/70/55 % и который держит щит. Должен быть сетевым и разрушаемым (см. самопроверку)."); d.CfgMarkPrefab = pl.S(d.Section, "MarkPrefab", "spawn_meteors", "Vanilla prefab dropped at a marked player from 70%: spawn_meteors (his meteor shower, its own damage) or an AoE such as aoe_nova.", "Ванильный префаб под отмеченным игроком с 70 %: spawn_meteors (его метеоритный дождь, урон свой) или AoE, например aoe_nova."); d.CfgMarkEffect = pl.S(d.Section, "MarkEffect", "vfx_prespawn", "Vanilla effect on the marked player before the meteors (players with the mod).", "Ванильный эффект на отмеченном игроке до метеоров (у игроков с модом)."); pl.BindCycle(d, "Cycle", "Regen: heals unless hit by frost within 3 s; Adapt: the most used damage type x0.6, the rest x1.1", "Regen — регенерация: лечится, если 3 с не получал мороза; Adapt — адаптация: самый частый тип урона ×0.6, остальные ×1.1", "Regen", "Adapt"); d.CfgRegen = pl.F(d.Section, "RegenPercentPerSecond", 0.3f, 0f, 5f, "Regeneration: % of max HP healed per second while no frost hit him for 3 s.", "Регенерация: % макс. HP в секунду, пока его 3 с не били морозом."); d.CfgAdaptFactor = pl.F(d.Section, "AdaptFactor", 0.6f, 0.1f, 1f, "Adaptation: damage of the type he adapted to (x).", "Адаптация: урон того типа, к которому он приспособился (×)."); d.CfgAdaptOthers = pl.F(d.Section, "AdaptOthers", 1.1f, 1f, 2f, "Adaptation: damage of every other type (x).", "Адаптация: урон всех остальных типов (×)."); d.CfgRoarInterval = pl.F(d.Section, "RoarInterval", 45f, 10f, 300f, "From 55%: seconds between his roars (x0.75 in Hard).", "С 55 %: секунд между его рёвами (×0.75 в Hard)."); d.CfgRoarRadius = pl.F(d.Section, "RoarRadius", 30f, 3f, 60f, "The roar hits every player within this distance of him (m).", "Рёв бьёт всех игроков ближе этого расстояния к нему (м)."); d.CfgRoarDamage = pl.F(d.Section, "RoarDamage", 30f, 0f, 200f, "Blunt damage of the roar; it also staggers (a block takes it) and tars (slows).", "Дробящий урон рёва; он ещё и сбивает с ног (блок принимает его) и покрывает смолой (замедляет)."); d.Gates["EchoOfModer"] = pl.B(d.Section, "EchoOfModer", def: false, "Experiment: at 10% Yagluth calls the echo of Moder (Aspect_Moder, half HP). Off by default.", "Эксперимент: на 10 % Яглут призывает эхо Модер (Aspect_Moder, половина HP). По умолчанию выкл."); }; return bossDef2; } private static BossDef Queen() { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) BossDef bossDef = new BossDef(); bossDef.Prefab = "SeekerQueen"; bossDef.Section = "15 Queen"; bossDef.CapSummons = true; BossDef bossDef2 = bossDef; Phase(bossDef2, 85f, "queen.85").Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "SeekerEgg_alwayshatch" }, Count = 1f, AnyProp = true }); PhaseDef phaseDef = Phase(bossDef2, 70f, "queen.70"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "SeekerEgg_alwayshatch" }, Count = 2f, AnyProp = true }); phaseDef.Acts.Add(new Act { Kind = ActKind.Marks, Prefabs = new string[1] { "SeekerQueen_spithit" }, Prop = "vfx_prespawn", MarkKey = "queen.mark", Count = 1f, Damage = 30f, DamageType = (DamageType)256 }); phaseDef = Phase(bossDef2, 55f, "queen.55"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "SeekerEgg_alwayshatch" }, Count = 2f, AnyProp = true }); phaseDef.Acts.Add(new Act { Kind = ActKind.Shield }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cycle, Duration = 30f, CooldownMin = 50f, CooldownMax = 70f, Delay = 60f, Variants = new List<CycleVariant> { new CycleVariant { Id = "Bloodthirst", Say = "queen.blood", EndKey = "queen.blood.end", Lifesteal = 40f }, new CycleVariant { Id = "AcidThorns", Say = "queen.acid", EndKey = "queen.acid.end", ThornsPercent = 10f, ThornsMin = 5f, RetaliateType = (DamageType)256 } } }); phaseDef = Phase(bossDef2, 45f, "queen.45"); phaseDef.Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "SeekerBrute" }, Count = 1f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cocoon, Prefabs = new string[1] { "Seeker" }, Count = 0.5f, Duration = 20f, Interval = 30f, Lifetime = 50f, MarkKey = "queen.cocoon" }); Phase(bossDef2, 30f, "queen.30").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Gjall" } }); Phase(bossDef2, 20f, "queen.20").Acts.Add(new Act { Kind = ActKind.Wave, Prefabs = new string[1] { "Tick" }, Count = 2f }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 720, 1080, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("Ruby", 2, 3, perPlayer: false)); bossDef2.Reward.Valuables.Add(Loot.Stack("Softtissue", 1f)); bossDef2.Reward.Valuables.Add(Loot.Stack("BlackCore", 1f)); bossDef2.Reward.Valuables.Add(Loot.Stack("Eitr", 1f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("FlametalOreNew", 0.5f)); bossDef2.Reward.Valuables.Add(new Loot("GemstoneRed", 1, 1, perPlayer: false)); bossDef2.Reward.Valuables.Add(new Loot("GemstoneGreen", 1, 1, perPlayer: false)); bossDef2.Reward.Valuables.Add(new Loot("GemstoneBlue", 1, 1, perPlayer: false)); bossDef2.Reward.Gear = new string[18] { "SwordMistwalker", "AxeJotunBane", "THSwordKrom", "KnifeSkollAndHati", "SpearCarapace", "AtgeirHimminAfl", "MaceEldner", "BowSpineSnap", "CrossbowArbalest", "ShieldCarapace", "ArmorCarapaceChest", "ArmorCarapaceLegs", "HelmetCarapace", "ArmorMageChest", "ArmorMageLegs", "HelmetMage", "StaffFireball", "StaffIceShards" }; bossDef2.Reward.NextGear = new string[11] { "SwordNiedhogg", "AxeBerzerkr", "THSwordSlayer", "SpearSplitner", "SledgeDemolisher", "BowAshlands", "CrossbowRipper", "ShieldFlametal", "ArmorFlametalChest", "ArmorFlametalLegs", "HelmetFlametal" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgNestPrefab = pl.S(d.Section, "EggPrefab", "SeekerEgg_alwayshatch", "Vanilla egg laid in clutches at 85/70/55%: they hatch on a timer and hold her shield until smashed or hatched.", "Ванильное яйцо, кладки на 85/70/55 %: вылупляются по таймеру и держат её щит, пока не разбиты или не вылупились."); d.CfgEggHatch = pl.F(d.Section, "EggHatchSeconds", 40f, 5f, 600f, "An egg hatches this long after it was laid (not when a player steps close), and only while the crowd around her is under the cap.", "Яйцо вылупляется через столько секунд после кладки (не от подхода игрока) и только пока монстров вокруг неё меньше лимита."); d.CfgHealthPerPlayer = pl.F(d.Section, "HealthPerPlayer", 0.3f, 0f, 2f, "Her HP grows by this per player beyond the first (instead of 02 Scaling / HealthPerPlayer): her fight is long and crowded as it is.", "Её HP растёт на столько за каждого игрока сверх первого (вместо 02 Scaling / HealthPerPlayer): её бой и так долгий и людный."); d.CfgCapSolo = pl.I(d.Section, "AddsCapSolo", 6, 1, 100, "At most this many monsters around her for a single player (instead of 09 Raid): seekers are fast and heavy on effects.", "Не больше стольких монстров вокруг неё для одного игрока (вместо 09 Raid): ищущие быстрые и тяжёлые по эффектам."); d.CfgCapPerPlayer = pl.I(d.Section, "AddsCapPerPlayer", 2, 0, 50, "Her cap grows by this for every player beyond the first.", "Её лимит растёт на столько за каждого игрока сверх первого."); d.CfgMarkPrefab = pl.S(d.Section, "MarkPrefab", "SeekerQueen_spithit", "Vanilla AoE prefab of the acid splash under a marked player from 70%.", "Ванильный AoE-префаб кислотного всплеска под отмеченным игроком с 70 %."); d.CfgMarkEffect = pl.S(d.Section, "MarkEffect", "vfx_prespawn", "Vanilla effect on the marked player before the acid (players with the mod).", "Ванильный эффект на отмеченном игроке до кислоты (у игроков с модом)."); d.CfgMarkDamage = pl.F(d.Section, "MarkDamage", 30f, 0f, 500f, "Poison damage of the acid splash (before 04 Marks DamageMultiplier).", "Урон ядом кислотного всплеска (до множителя из 04 Marks)."); pl.BindCycle(d, "Cycle", "Bloodthirst: her hits on players heal her; AcidThorns: every hit on her is paid back with poison", "Bloodthirst — кровожадность: её удары по игрокам лечат её; AcidThorns — кислотные шипы: каждый удар по ней возвращается ядом", "Bloodthirst", "AcidThorns"); d.CfgLifesteal = pl.F(d.Section, "BloodthirstPercent", 40f, 0f, 200f, "Bloodthirst: % of the damage her hits really deal to players (after block and armor; a blocked or dodged hit heals nothing) she heals.", "Кровожадность: сколько % урона, реально прошедшего по игрокам (после блока и брони; заблокированный или увёрнутый удар не лечит), она лечит."); d.CfgCycleThorns = pl.F(d.Section, "AcidThornsPercent", 10f, 0f, 100f, "Acid thorns: % of each hit's damage dealt back as poison to the attacker (at least 5, at most once a second per player).", "Кислотные шипы: % урона удара, который возвращается атакующему ядом (не меньше 5, не чаще раза в секунду на игрока)."); }; return bossDef2; } private static BossDef Fader() { //IL_0222: Unknown result type (might be due to invalid IL or missing references) BossDef bossDef = new BossDef(); bossDef.Prefab = "Fader"; bossDef.Section = "16 Fader"; bossDef.CapSummons = true; BossDef bossDef2 = bossDef; bossDef2.CycleCdMinDefault = 100f; bossDef2.CycleCdMaxDefault = 140f; Phase(bossDef2, 85f, "fader.85").Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_CharredStone" }, Count = 1f }); PhaseDef phaseDef = Phase(bossDef2, 70f, "fader.70"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_CharredStone" }, Count = 1f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "FallenValkyrie" } }); phaseDef = Phase(bossDef2, 55f, "fader.55"); phaseDef.Acts.Add(new Act { Kind = ActKind.Nest, Prefabs = new string[1] { "Spawner_CharredStone" }, Count = 2f }); phaseDef.Acts.Add(new Act { Kind = ActKind.Shield }); phaseDef.Acts.Add(new Act { Kind = ActKind.Cycle, Duration = 30f, CooldownMin = 100f, CooldownMax = 140f, Delay = 60f, Variants = new List<CycleVariant> { new CycleVariant { Id = "Molten", Say = "fader.molten", EndKey = "fader.molten.end", MeleeRange = 6f, RangedFactor = 1.5f, Retaliate = 15f, RetaliateType = (DamageType)32 }, new CycleVariant { Id = "AshVeil", Say = "fader.ash", EndKey = "fader.ash.end", MeleeRange = 6f, MeleeFactor = 1.5f } } }); Phase(bossDef2, 45f, "fader.45").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Morgen" } }); Phase(bossDef2, 30f, "fader.30").Acts.Add(new Act { Kind = ActKind.Lieutenant, Prefabs = new string[1] { "Charred_Melee_Dyrnwyn" } }); bossDef2.Reward.Valuables.Add(new Loot("Coins", 900, 1500, perPlayer: true)); bossDef2.Reward.Valuables.Add(new Loot("GemstoneRed", 1, 2, perPlayer: false)); bossDef2.Reward.Valuables.Add(new Loot("GemstoneGreen", 1, 2, perPlayer: false)); bossDef2.Reward.Valuables.Add(new Loot("GemstoneBlue", 1, 2, perPlayer: false)); bossDef2.Reward.Valuables.Add(Loot.Stack("FlametalOreNew", 1f)); bossDef2.Reward.Valuables.Add(Loot.Stack("MoltenCore", 1f)); bossDef2.Reward.NextBiome.Add(Loot.Stack("FrostCore", 0.5f)); bossDef2.Reward.Gear = new string[13] { "SwordNiedhogg", "AxeBerzerkr", "THSwordSlayer", "SpearSplitner", "SledgeDemolisher", "BowAshlands", "CrossbowRipper", "ShieldFlametal", "ShieldFlametalTower", "ArmorFlametalChest", "ArmorFlametalLegs", "HelmetFlametal", "StaffGreenRoots" }; bossDef2.BindExtra = delegate(ExtendedBossesPlugin pl, BossDef d) { d.CfgNestPrefab = pl.S(d.Section, "NestPrefab", "Spawner_CharredStone", "Vanilla destructible spawner of charred at 85/70/55%. Alternative: Spawner_CharredCross.", "Ванильный разрушаемый спавнер обугленных на 85/70/55 %. Альтернатива — Spawner_CharredCross."); d.CfgHealthPerPlayer = pl.F(d.Section, "HealthPerPlayer", 0.3f, 0f, 2f, "His HP grows by this per player beyond the first (instead of 02 Scaling / HealthPerPlayer): 25000 HP and a vanilla fight that is hard as it is - 0.3 is the vanilla growth.", "Его HP растёт на столько за каждого игрока сверх первого (вместо 02 Scaling / HealthPerPlayer): 25000 HP и ванильный бой и так тяжёлый — 0.3 как в ванили."); d.CfgCapSolo = pl.I(d.Section, "AddsCapSolo", 6, 1, 100, "At most this many monsters around him for a single player (instead of 09 Raid): his roar calls charred too, and the arena is in fire.", "Не больше стольких монстров вокруг него для одного игрока (вместо 09 Raid): его рёв тоже зовёт обугленных, а арена в огне."); d.CfgCapPerPlayer = pl.I(d.Section, "AddsCapPerPlayer", 2, 0, 50, "His cap grows by this for every player beyond the first.", "Его лимит растёт на столько за каждого игрока сверх первого."); pl.BindCycle(d, "Cycle", "Molten: hits from afar x1.5, close attackers burn; AshVeil: close hits x1.5", "Molten — раскалённая броня: удары издалека ×1.5, бьющие вблизи обжигаются; AshVeil — пепельная завеса: удары вблизи ×1.5", "Molten", "AshVeil"); d.CfgCycleRanged = pl.F(d.Section, "MoltenRangedFactor", 1.5f, 1f, 3f, "Molten armor: damage of hits from farther than 6 m (x).", "Раскалённая броня: урон ударов дальше 6 м (×)."); d.CfgCycleRetaliate = pl.F(d.Section, "MoltenFireDamage", 15f, 0f, 200f, "Molten armor: fire dealt back to a close attacker per hit (at most once a second per player; 0 = none).", "Раскалённая броня: огонь, который получает атакующий вблизи за удар (не чаще раза в секунду на игрока; 0 — нет)."); d.CfgCycleMelee = pl.F(d.Section, "AshVeilMeleeFactor", 1.5f, 1f, 3f, "Ash veil: damage of hits from within 6 m (x).", "Пепельная завеса: урон ударов ближе 6 м (×)."); }; return bossDef2; } private void BindCapConfig() { _cfgCapBase = I("09 Raid", "AddsCapSolo", 8, 1, 100, "At most this many monsters around a boss for a single player (nests, totems, waves and slime stop at it).", "Не больше стольких монстров вокруг босса для одного игрока (гнёзда, тотемы, волны и слизь на этом останавливаются)."); _cfgCapPerPlayer = I("09 Raid", "AddsCapPerPlayer", 3, 0, 50, "The cap grows by this for every player beyond the first.", "Лимит растёт на столько за каждого игрока сверх первого."); _cfgCapRadius = F("09 Raid", "AddsCapRadius", 50f, 10f, 150f, "Monsters within this distance of the boss count towards the cap.", "Монстры ближе этого расстояния к боссу считаются в лимит."); _cfgTrimAt = F("09 Raid", "AddsTrimAt", 1.5f, 1.1f, 10f, "When the monsters around a boss reach the cap times this, the oldest of its own adds leave until the cap (lieutenants stay, vanilla monsters are never removed).", "Когда монстров вокруг босса больше лимита во столько раз, самые старые из его аддов исчезают до лимита (лейтенанты остаются, ванильных монстров не трогает)."); _cfgWaveLifetime = F("09 Raid", "WaveLifetime", 90f, 0f, 3600f, "Seconds an add of a wave lives if nobody kills it (0 = until killed).", "Сколько секунд живёт адд волны, если его не убили (0 — пока не убьют)."); } internal int AddsCap(Character boss) { BossDef bossDef = BossOf(Zdo((Component)(object)boss)); int num = ((bossDef != null && bossDef.CfgCapSolo != null) ? Si(bossDef.CfgCapSolo) : Si(_cfgCapBase)); int num2 = ((bossDef != null && bossDef.CfgCapPerPlayer != null) ? Si(bossDef.CfgCapPerPlayer) : Si(_cfgCapPerPlayer)); return num + num2 * (GroupSize(boss) - 1); } internal int CapRoom(Character boss) { return Mathf.Max(0, AddsCap(boss) - MonstersNear(boss)); } private Character ModBoss(ZDOID bossId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (bossId == ZDOID.None || (Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject val = ZNetScene.instance.FindInstance(bossId); Character val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Character>() : null); if ((Object)(object)val2 == (Object)null || val2.Is