Иконка ресурса

FREE DangerousTreasures : 3.0.0 3.0.0

Нет прав для скачивания
C#:
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Plugins.DangerousTreasuresExtensionMethods;
using Rust;
using Rust.Ai.Gen2;
using Rust.Ai.Gen2.Nav;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
namespace Oxide.Plugins {
    [Info("Dangerous Treasures", "nivex", "3.0.0")]
    [Description("Event with treasure chests.")]
    internal class DangerousTreasures : RustPlugin {
        [PluginReference]
        Plugin ZoneManager, Economics, ServerRewards, GUIAnnouncements, MarkerManager, Kits, Duelist, RaidableBases, AbandonedBases, Notify, AdvancedAlerts, Clans, Friends;
        private new const string Name = "Dangerous Treasures";
        private bool wipeChestsSeed;
        private StoredData data = new();
        private List<int> BlockedLayers = new() {
            (int)Layer.Water, (int)Layer.Construction, (int)Layer.Trigger, (int)Layer.Prevent_Building, (int)Layer.Deployed, (int)Layer.Tree, (int)Layer.Clutter
        }
        ;
        private Dictionary<ulong, HumanoidBrain> HumanoidBrains = new();
        private List<MonumentInfoEx> _allowedMonuments = new();
        private List<MonumentInfoEx> monuments = new();
        private Dictionary<Vector3, ZoneInfo> managedZones = new();
        private Dictionary<NetworkableId, TreasureChest> treasureChests = new();
        private Dictionary<NetworkableId, string> looters = new();
        private Dictionary<string, ItemDefinition> _definitions = new();
        private Dictionary<string, SkinInfo> Skins = new();
        private List<ulong> newmanProtections = new();
        private List<ulong> indestructibleWarnings = new();
        // indestructible messages limited to once every 10 seconds
        private List<ulong> drawGrants = new();
        // limit draw to once every 15 seconds by default
        private List<int> obstructionLayers = new() {
            Layers.Mask.Player_Server, Layers.Mask.Construction, Layers.Mask.Deployed
        }
        ;
        private List<string> _blockedColliders = new() {
            "powerline_", "invisible_", "TopCol", "train", "swamp_", "floating_"
        }
        ;
        private List<string> underground = new() {
            "Cave", "Sewer Branch", "Military Tunnel", "Underwater Lab", "Train Tunnel"
        }
        ;
        private List<Vector3> _gridPositions = new();
        private List<Vector3> _gridPositionsSrc = new();
        private bool IsGridReady;
        private bool IsMonumentsReady;
        private Coroutine _gridCo;
        private RaycastHit[] sharedRockHits = new RaycastHit[256];
        private Collider[] sharedRockColliders = new Collider[256];
        private const int TARGET_MASK = 8454145;
        private const int targetMask = Layers.Mask.World | Layers.Mask.Terrain | Layers.Mask.Default;
        private const int visibleMask = Layers.Mask.Deployed | Layers.Mask.Construction | targetMask;
        private const int obstructionLayer = Layers.Mask.Player_Server | Layers.Mask.Construction | Layers.Mask.Deployed;
        private const int heightLayer = TARGET_MASK | Layers.Mask.Construction | Layers.Mask.Deployed | Layers.Mask.Clutter;
        private StringBuilder _sb = new();
        private Vector3 sd_customPos;
        private ulong BotIdCounter = 624922525;
        private Dictionary<int, double> eventRetries = new();
        public class ZoneInfo {
            public Vector3 Position;
            public Vector3 Size;
            public float Distance;
            public OBB OBB;
        }
        public class SkinInfo {
            public List<ulong> skins = new();
            public List<ulong> workshopSkins = new();
            public List<ulong> importedSkins = new();
            public List<ulong> allSkins = new();
        }
        private class PlayerInfo {
            public int StolenChestsTotal;
            public int StolenChestsSeed;
            public PlayerInfo() {
            }
        }
        private class StoredData {
            public Dictionary<string, PlayerInfo> Players = new();
            [JsonProperty(PropertyName = "Seconds Until Event")]
            public Dictionary<int, double> SecondsUntilEvent = new() {
                [0]
                = double.MinValue
            }
            ;
            public string CustomPosition;
            public int TotalEvents = 0;
            public StoredData() {
            }
        }
        public class HumanoidNPC : ScientistNPC {
            public new HumanoidBrain Brain;
            public TreasureChest tc;
            public string DisplayNameOverride;
            public DifficultyLevel Options;
            public Configuration config;
            public DangerousTreasures Instance;
            public new Translate.Phrase LootPanelTitle => displayName;
            public override string Categorize() => "Humanoid";
            public override bool ShouldDropActiveItem() => false;
            public override string displayName => DisplayNameOverride;
            public override void AttackerInfo(ProtoBuf.PlayerLifeStory.DeathInfo info) {
                info.attackerName = displayName;
                info.attackerSteamID = userID;
                info.inflictorName = inventory?.containerBelt?.GetSlot(0)?.info?.shortname;
                if (Brain != null) info.attackerDistance = Vector3.Distance(Brain.ServerPosition, Brain.AttackPosition);
            }
            public override void OnDied(HitInfo info) {
                BasePlayer.bots.Remove(this);
                if (Brain != null) Brain.DisableShouldThink();
                if (Instance != null && tc != null) {
                    svActiveItemID = default;
                    SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                    tc.npcs.Remove(this);
                    if (tc.whenNpcsDie && tc.npcs.Count == 0) tc.Unlock();
                    if (config.Unlock.LockToPlayerOnNpcDeath) tc.TrySetOwner(info);
                    if (Options.Event.DestructTimeResetsWhenKilled && info != null && info.Initiator.Is(out BasePlayer attacker) && attacker.userID.IsSteamId()) tc.SetDestructTime();
                }
                base.OnDied(info);
            }
            public override void DoServerDestroy() {
                if (tc != null && tc.npcs != null) tc.npcs.Remove(this);
                BasePlayer.bots.Remove(this);
                if (Brain != null) {
                    AttackEntity attackEntity = Brain._attackEntity;
                    if (!attackEntity.IsKilled()) attackEntity.SetHeld(false);
                    Brain.DisableShouldThink();
                }
                base.DoServerDestroy();
                BasePlayer.freeBotIds.Remove(userID);
            }
            public override BaseCorpse CreateCorpse(PlayerFlags flagsOnDeath, Vector3 posOnDeath, Quaternion rotOnDeath, List<TriggerBase> triggersOnDeath, bool forceServerSide = false) {
                if (inventory == null || Brain == null) {
                    inventory.SafelyStrip();
                    CheckCorpse(null);
                    return null;
                }
                bool keepInventory = !(Brain.isMurderer ? Options.NPC.Murderers.DespawnInventory : Options.NPC.Scientists.DespawnInventory);
                bool hasPrefabLoot = !LootSpawnSlots.IsNullOrEmpty();
                if (!keepInventory && !hasPrefabLoot) {
                    inventory.SafelyStrip();
                    CheckCorpse(null);
                    return null;
                }
                if (keepInventory) inventory.containerWear.SafelyRemove("gloweyes");
                else inventory.SafelyStrip();
                if (!RemoveOwnershipPass() && !hasPrefabLoot) {
                    CheckCorpse(null);
                    return null;
                }
                PlayerCorpse corpse = DropCorpse("assets/prefabs/player/player_corpse.prefab") as PlayerCorpse;
                if (corpse == null) {
                    CheckCorpse(null);
                    return null;
                }
                if (NavAgent != null) corpse.transform.position += Vector3.down * NavAgent.baseOffset;
                corpse.TakeFrom(this, inventory.containerMain, inventory.containerWear, inventory.containerBelt);
                corpse.playerName = displayName;
                corpse.playerSteamID = userID;
                corpse.skinID = 14922525;
                corpse.Spawn();
                if (corpse.IsKilled()) {
                    CheckCorpse(null);
                    return null;
                }
                corpse.TakeChildren(this);
                var alternate = Brain.isMurderer ? Options.NPC.Murderers.Alternate : Options.NPC.Scientists.Alternate;
                bool canPopulateLoot = !alternate.CallHook || Interface.CallHook("OnCorpsePopulate", this, corpse) == null;
                if (corpse.IsKilled()) {
                    CheckCorpse(null);
                    return null;
                }
                if (canPopulateLoot && !LootSpawnSlots.IsNullOrEmpty()) {
                    foreach (var lootSpawnSlot in LootSpawnSlots) {
                        for (int k = 0; k < lootSpawnSlot.numberToSpawn; k++) {
                            if (UnityEngine.Random.Range(0f, 1f) <= lootSpawnSlot.probability) lootSpawnSlot.definition.SpawnIntoContainer(corpse.containers[0]);
                        }
                    }
                }
                CheckCorpse(corpse);
                return corpse;
            }
            private void CheckCorpse(PlayerCorpse corpse) {
                if (corpse != null && Brain != null) {
                    float time = Brain.isMurderer ? (Options.NPC.Murderers.DespawnInventory ? Options.NPC.Murderers.DespawnInventoryTime : Options.NPC.Murderers.CorpseDespawnTime) : (Options.NPC.Scientists.DespawnInventory ? Options.NPC.Scientists.DespawnInventoryTime : Options.NPC.Scientists.CorpseDespawnTime);
                    corpse.Invoke(corpse.SafelyKill, time);
                    corpse.playerName = displayName;
                }
                if (Brain != null) UnityEngine.Object.Destroy(Brain);
            }
            private bool RemoveOwnershipPass() {
                if (!Instance.config.BlockPaidContent) return true;
                using var itemList = Facepunch.Pool.Get<PooledList<Item>>();
                inventory.GetAllItems(itemList);
                bool hasItems = false;
                for (int i = itemList.Count - 1; i >= 0; i--) {
                    Item item = itemList[i];
                    if (!Instance.RequiresOwnership(item.info, item.skin)) {
                        hasItems = true;
                        continue;
                    }
                    item.GetHeldEntity().SafelyKill();
                    item.RemoveFromContainer();
                    item.Remove(0f);
                }
                return hasItems;
            }
        }
        public class HumanoidBrain : ScientistBrain {
            public void DisableShouldThink() {
                isDisabled = true;
                lastWarpTime = float.MaxValue;
                sleeping = true;
                SetEnabled(false);
                try {
                    CancelInvoke();
                }
                catch {
                }
                AIThinkManager._processQueue.Remove(npc);
                if (HumanoidBrains.Remove(uid) && HumanoidBrains.Count == 0 && Instance.Manager != null) {
                    if (!config.NewmanMode.Harm) Instance.Unsubscribe(nameof(OnNpcTarget));
                    Instance.Unsubscribe(nameof(OnNpcResume));
                    Instance.Unsubscribe(nameof(OnNpcDestinationSet));
                    Instance.Unsubscribe(nameof(CanBradleyApcTarget));
                }
                if (Rust.Application.isQuitting) {
                    return;
                }
                if (npc != null && BaseEntity.Query.Server != null) {
                    BaseEntity.Query.Server.RemoveBrain(npc);
                }
                LeaveGroup();
            }
            internal DangerousTreasures Instance;
            internal Dictionary<ulong, HumanoidBrain> HumanoidBrains;
            internal enum AttackType {
                BaseProjectile, FlameThrower, Melee, Water, None
            }
            internal string displayName;
            internal Transform NpcTransform;
            internal HumanoidNPC npc;
            internal AttackEntity _attackEntity;
            internal FlameThrower flameThrower;
            internal LiquidWeapon liquidWeapon;
            internal BaseMelee baseMelee;
            internal BaseProjectile baseProjectile;
            internal BasePlayer AttackTarget;
            internal Transform AttackTransform;
            internal TreasureChest tc;
            internal NpcSettings Settings;
            internal List<Vector3> positions;
            internal Vector3 DestinationOverride;
            internal bool isDisabled;
            internal bool InitializedAI;
            internal bool isMurderer;
            internal ulong uid;
            internal float lastWarpTime;
            internal float softLimitSenseRange;
            internal float nextAttackTime;
            internal float attackRange;
            internal float attackCooldown;
            internal AttackType attackType = AttackType.None;
            internal BaseNavigator.NavigationSpeed CurrentSpeed = BaseNavigator.NavigationSpeed.Normal;
            internal DifficultyLevel Options => tc.Options;
            internal Vector3 AttackPosition => AttackTransform == null ? default : AttackTransform.position;
            internal Vector3 ServerPosition => NpcTransform == null ? default : NpcTransform.position;
            internal Configuration config;
            internal AttackEntity AttackEntity {
                get {
                    if (_attackEntity.IsNull()) {
                        IdentifyWeapon();
                    }
                    return _attackEntity;
                }
            }
            public void UpdateWeapon(AttackEntity attackEntity, ItemId uid) {
                npc.UpdateActiveItem(uid);
                if (attackEntity is Chainsaw cs) {
                    cs.ServerNPCStart();
                }
                npc.damageScale = 1f;
                attackEntity.TopUpAmmo();
                attackEntity.SetHeld(true);
            }
            internal void IdentifyWeapon() {
                _attackEntity = GetEntity().GetAttackEntity();
                attackRange = 0f;
                attackCooldown = 99999f;
                attackType = AttackType.None;
                baseMelee = null;
                flameThrower = null;
                liquidWeapon = null;
                if (_attackEntity.IsNull()) {
                    return;
                }
                Action action = _attackEntity.ShortPrefabName switch {
                    "double_shotgun.entity" or "shotgun_pump.entity" or "shotgun_waterpipe.entity" or "spas12.entity" or "blowpipe.entity" or "boomerang.entity" => () => {
                        SetAttackRestrictions(AttackType.BaseProjectile, 30f, 0f, 30f);
                    }
                    , "ak47u.entity" or "ak47u_ice.entity" or "bolt_rifle.entity" or "glock.entity" or "hmlmg.entity" or "l96.entity" or "lr300.entity" or "m249.entity" or "m39.entity" or "m92.entity" or "mp5.entity" or "nailgun.entity" or "pistol_eoka.entity" or "pistol_revolver.entity" or "pistol_semiauto.entity" or "python.entity" or "semi_auto_rifle.entity" or "thompson.entity" or "smg.entity" => () => {
                        SetAttackRestrictions(AttackType.BaseProjectile, 300f, 0f, 150f);
                    }
                    , "snowballgun.entity" => () => {
                        SetAttackRestrictions(AttackType.BaseProjectile, 15f, 0.1f, 15f);
                    }
                    , "chainsaw.entity" or "jackhammer.entity" => () => {
                        baseMelee = _attackEntity as BaseMelee;
                        SetAttackRestrictions(AttackType.Melee, 2.5f, (_attackEntity.animationDelay + _attackEntity.deployDelay) * 2f);
                    }
                    , "axe_salvaged.entity" or "bone_club.entity" or "butcherknife.entity" or "candy_cane.entity" or "hammer_salvaged.entity" or "hatchet.entity" or "icepick_salvaged.entity" or "knife.combat.entity" or "knife_bone.entity" or "longsword.entity" or "mace.baseballbat" or "mace.entity" or "machete.weapon" or "pickaxe.entity" or "pitchfork.entity" or "salvaged_cleaver.entity" or "salvaged_sword.entity" or "sickle.entity" or "spear_stone.entity" or "spear_wooden.entity" or "stone_pickaxe.entity" or "stonehatchet.entity" => () => {
                        baseMelee = _attackEntity as BaseMelee;
                        SetAttackRestrictions(AttackType.Melee, 2.5f, _attackEntity.animationDelay + _attackEntity.deployDelay);
                    }
                    , "flamethrower.entity" => () => {
                        flameThrower = _attackEntity as FlameThrower;
                        SetAttackRestrictions(AttackType.FlameThrower, 10f, (_attackEntity.animationDelay + _attackEntity.deployDelay) * 2f);
                    }
                    , "compound_bow.entity" or "crossbow.entity" or "speargun.entity" or "bow_hunting.entity" => () => {
                        SetAttackRestrictions(AttackType.BaseProjectile, 200f, (_attackEntity.animationDelay + _attackEntity.deployDelay) * 1.25f, 150f);
                    }
                    , "watergun.entity" or "waterpistol.entity" => () => {
                        if ((liquidWeapon = _attackEntity as LiquidWeapon) != null) {
                            liquidWeapon.AutoPump = true;
                            SetAttackRestrictions(AttackType.Water, 10f, 2f);
                        }
                    }
                    , _ => () => _attackEntity = null
                }
                ;
                action();
            }
            private void SetAttackRestrictions(AttackType attackType, float attackRange, float attackCooldown, float effectiveRange = 0f) {
                if (attackType == AttackType.BaseProjectile) {
                    baseProjectile = _attackEntity as BaseProjectile;
                    if (baseProjectile != null) {
                        baseProjectile.MuzzlePoint ??= baseProjectile.transform;
                    }
                }
                if (effectiveRange != 0f) {
                    _attackEntity.effectiveRange = effectiveRange;
                }
                this.attackType = attackType;
                this.attackRange = attackRange;
                this.attackCooldown = attackCooldown;
            }
            public bool ValidTarget => AttackTransform != null && !AttackTarget.IsKilled() && !ShouldForgetTarget(AttackTarget);
            public override void OnDestroy() {
                DisableShouldThink();
                if (InitializedAI) Count--;
            }
            public override void InitializeAI() {
                if (isDisabled) {
                    return;
                }
                base.InitializeAI();
                InitializedAI = true;
                base.ForceSetAge(0f);
                NpcTransform = GetEntity().transform;
                Pet = false;
                sleeping = false;
                UseAIDesign = true;
                AllowedToSleep = false;
                HostileTargetsOnly = false;
                AttackRangeMultiplier = 2f;
                MaxGroupSize = 0;
                Senses.Init(owner : GetEntity(), brain : this, memoryDuration : 5f, range : 50f, targetLostRange : 75f, visionCone : -1f, checkVision : false, checkLOS : true, ignoreNonVisionSneakers : true, listenRange : 15f, hostileTargetsOnly : false, senseFriendlies : false, ignoreSafeZonePlayers : false, senseTypes : EntityType.Player, refreshKnownLOS : true );
                //senseTypes: config.Settings.Management.TargetNpcs? EntityType.Player | EntityType.BasePlayerNPC : EntityType.Player,
                CanUseHealingItems = true;
            }
            public override void AddStates() {
                if (isDisabled) {
                    return;
                }
                base.AddStates();
                states[AIState.Attack] = new AttackState(this);
            }
            public class AttackState : BaseAttackState {
                private new HumanoidBrain brain;
                private global : : HumanNPC npc;
                private Transform NpcTransform;
                private new IAIAttack attack => brain.Senses.ownerAttack;
                public AttackState(HumanoidBrain humanoidBrain) {
                    base.brain = brain = humanoidBrain;
                    base.AgrresiveState = true;
                    npc = brain.GetBrainBaseEntity() as global : : HumanNPC;
                    NpcTransform = npc.transform;
                }
                public override void StateEnter(BaseAIBrain _brain, BaseEntity _entity) {
                    if (_brain != null && NpcTransform != null && brain.ValidTarget) {
                        if (InAttackRange()) {
                            StartAttacking();
                        }
                        if (brain.CanUseNavMesh()) {
                            brain.Navigator.SetDestination(brain.DestinationOverride, BaseNavigator.NavigationSpeed.Fast, 0f, 0f);
                        }
                    }
                }
                public override void StateLeave(BaseAIBrain _brain, BaseEntity _entity) {
                }
                private new void StopAttacking() {
                    if (attack != null) {
                        attack.StopAttacking();
                        brain.AttackTarget = null;
                        brain.AttackTransform = null;
                        brain.Navigator.ClearFacingDirectionOverride();
                    }
                }
                public override StateStatus StateThink(float delta, BaseAIBrain _brain, BaseEntity _entity) {
                    if (_brain == null || NpcTransform == null || attack == null) {
                        return StateStatus.Error;
                    }
                    if (brain.isDisabled || !brain.ValidTarget) {
                        StopAttacking();
                        return StateStatus.Finished;
                    }
                    if (brain.Senses.ignoreSafeZonePlayers && brain.AttackTarget.InSafeZone()) {
                        return StateStatus.Error;
                    }
                    if (brain.CanUseNavMesh() && !brain.Navigator.SetDestination(brain.DestinationOverride, BaseNavigator.NavigationSpeed.Fast, 0f, 0f)) {
                        return StateStatus.Error;
                    }
                    if (!brain.CanShoot()) {
                        brain.Forget();
                        StopAttacking();
                        return StateStatus.Finished;
                    }
                    if (InAttackRange()) {
                        StartAttacking();
                    }
                    return StateStatus.Running;
                }
                private bool InAttackRange() {
                    return !npc.IsWounded() && brain.AttackTransform != null && attack.CanAttack(brain.AttackTarget) && brain.IsInAttackRange() && brain.CanSeeTarget(brain.AttackTarget);
                }
                private void StartAttacking() {
                    if (brain.AttackTransform == null) {
                        return;
                    }
                    brain.SetAimDirection();
                    if (!brain.CanShoot() || brain.IsAttackOnCooldown()) {
                        return;
                    }
                    if (brain.attackType == AttackType.BaseProjectile) {
                        RealisticShotTest();
                    }
                    else if (brain.attackType == AttackType.FlameThrower) {
                        brain.UseFlameThrower();
                    }
                    else if (brain.attackType == AttackType.Water) {
                        brain.UseWaterGun();
                    }
                    else brain.MeleeAttack();
                }
                private void RealisticShotTest() {
                    if (NpcTransform == null || brain.baseProjectile == null || brain.baseProjectile.primaryMagazine == null) {
                        return;
                    }
                    if (brain.AttackTarget.IsNpc) {
                        var faction = brain.AttackTarget.faction;
                        brain.AttackTarget.faction = BaseCombatEntity.Faction.Horror;
                        npc.ShotTest(brain.AttackPosition.Distance(brain.ServerPosition));
                        if (brain.AttackTarget != null) brain.AttackTarget.faction = faction;
                    }
                    else npc.ShotTest(brain.AttackPosition.Distance(brain.ServerPosition));
                }
            }
            private bool init;
            public void Init() {
                if (init) return;
                init = true;
                lastWarpTime = Time.time;
                npc.spawnPos = tc.containerPos;
                npc.AdditionalLosBlockingLayer = visibleMask;
                SetupNavigator(GetEntity(), GetComponent<BaseNavigator>(), tc.Radius);
            }
            private void Converge() {
                foreach (var brain in HumanoidBrains.Values) {
                    if (brain != null && brain.NpcTransform != null && brain != this && brain.attackType == attackType && brain.CanConverge(npc)) {
                        brain.SetTarget(AttackTarget, false);
                    }
                }
            }
            public void Forget() {
                Senses.Players.Clear();
                Senses.Memory.All.Clear();
                Senses.Memory.Threats.Clear();
                Senses.Memory.Targets.Clear();
                Senses.Memory.Players.Clear();
                Navigator.ClearFacingDirectionOverride();
                DestinationOverride = GetRandomRoamPosition();
                SenseRange = ListenRange = isMurderer ? Settings.Murderers.AggressionRange : Settings.Scientists.AggressionRange;
                Senses.targetLostRange = TargetLostRange = SenseRange * 1.25f;
                AttackTarget = null;
                AttackTransform = null;
                TryReturnHome();
            }
            private void RandomMove(float radius) {
                var to = AttackPosition + UnityEngine.Random.onUnitSphere * radius;
                to.y = TerrainMeta.HeightMap.GetHeight(to);
                SetDestination(to);
            }
            public void SetupNavigator(BaseCombatEntity owner, BaseNavigator navigator, float distance) {
                navigator.CanUseNavMesh = !Rust.Ai.AiManager.nav_disable;
                navigator.MaxRoamDistanceFromHome = navigator.BestMovementPointMaxDistance = navigator.BestRoamPointMaxDistance = distance * 0.85f;
                navigator.DefaultArea = "Walkable";
                navigator.topologyPreference = ((TerrainTopology.Enum)TerrainTopology.EVERYTHING);
                navigator.Agent.agentTypeID = NavMesh.GetSettingsByIndex(1).agentTypeID;
                // 0:0, 1: -1372625422, 2: 1479372276, 3: -1923039037
                navigator.MaxWaterDepth = 3f;
                if (navigator.CanUseNavMesh) {
                    navigator.Init(owner, navigator.Agent);
                }
            }
            public Vector3 GetAimDirection() {
                if (Navigator.IsOverridingFacingDirection) {
                    return Navigator.FacingDirectionOverride;
                }
                if (InRange2D(AttackPosition, ServerPosition, 1f)) {
                    return npc.eyes.BodyForward();
                }
                return (AttackPosition - ServerPosition).normalized;
            }
            private void SetAimDirection() {
                Navigator.SetFacingDirectionEntity(AttackTarget);
                npc.SetAimDirection(GetAimDirection());
            }
            private void SetDestination() {
                SetDestination(GetRandomRoamPosition());
            }
            private void SetDestination(Vector3 destination) {
                if (!CanLeave(destination)) {
                    if (attackType != AttackType.BaseProjectile) {
                        destination = ((destination.XZ3D() - tc.containerPos.XZ3D()).normalized * (tc.Radius * 0.75f)) + tc.containerPos;
                        destination += UnityEngine.Random.onUnitSphere * (tc.Radius * 0.2f);
                    }
                    else {
                        destination = GetRandomRoamPosition();
                    }
                    CurrentSpeed = BaseNavigator.NavigationSpeed.Normal;
                }
                if (destination != DestinationOverride) {
                    destination.y = TerrainMeta.HeightMap.GetHeight(destination);
                    DestinationOverride = destination;
                }
                Navigator.SetCurrentSpeed(CurrentSpeed);
                if (Navigator.CurrentNavigationType == BaseNavigator.NavigationType.None && !Rust.Ai.AiManager.ai_dormant && !Rust.Ai.AiManager.nav_disable) {
                    Navigator.SetCurrentNavigationType(BaseNavigator.NavigationType.NavMesh);
                }
                if (CanUseNavMesh() && !Navigator.SetDestination(destination, CurrentSpeed)) {
                    Navigator.Destination = destination;
                    npc.finalDestination = destination;
                }
            }
            public bool CanUseNavMesh() => Navigator.CanUseNavMesh && !Navigator.StuckOffNavmesh;
            public bool SetTarget(BasePlayer player, bool converge = true) {
                if (isDisabled) {
                    return false;
                }
                if (NpcTransform == null) {
                    DisableShouldThink();
                    Destroy(this);
                    return false;
                }
                if (player.IsKilled() || player.limitNetworking) {
                    return false;
                }
                if (AttackTarget == player) {
                    return true;
                }
                if (npc.lastGunShotTime < Time.time + 2f) {
                    npc.nextTriggerTime = Time.time + 0.2f;
                    nextAttackTime = Time.realtimeSinceStartup + 0.2f;
                }
                Senses.Memory.SetKnown(player, npc, null);
                npc.lastAttacker = player;
                AttackTarget = player;
                AttackTransform = player.transform;
                if (!IsInSenseRange(AttackPosition)) {
                    SenseRange = ListenRange = (isMurderer ? Settings.Murderers.AggressionRange : Settings.Scientists.AggressionRange) + AttackPosition.Distance(ServerPosition);
                    TargetLostRange = SenseRange + (SenseRange * 0.25f);
                }
                else {
                    SenseRange = ListenRange = softLimitSenseRange;
                    TargetLostRange = softLimitSenseRange * 1.25f;
                }
                if (converge) {
                    Converge();
                }
                return true;
            }
            private void TryReturnHome() {
                if (Settings.CanLeave && !IsInHomeRange()) {
                    CurrentSpeed = BaseNavigator.NavigationSpeed.Normal;
                    Warp();
                }
            }
            private void TryToAttack() => TryToAttack(null);
            private void TryToAttack(BasePlayer attacker) {
                if (isDisabled) {
                    return;
                }
                if ((attacker ??= GetBestTarget()).IsNull()) {
                    return;
                }
                if (ShouldForgetTarget(attacker)) {
                    Forget();
                    return;
                }
                if (!SetTarget(attacker) || AttackTransform == null || !CanSeeTarget(attacker)) {
                    return;
                }
                if (attackType == AttackType.BaseProjectile) {
                    TryScientistActions();
                }
                else {
                    TryMurdererActions();
                }
                SwitchToState(AIState.Attack, -1);
            }
            private void TryMurdererActions() {
                CurrentSpeed = BaseNavigator.NavigationSpeed.Fast;
                if (!IsInReachableRange()) {
                    RandomMove(15f);
                }
                else if (!IsInAttackRange()) {
                    if (attackType == AttackType.FlameThrower) {
                        RandomMove(attackRange);
                    }
                    else {
                        SetDestination(AttackPosition);
                    }
                }
            }
            private void TryScientistActions() {
                CurrentSpeed = BaseNavigator.NavigationSpeed.Fast;
                SetDestination();
            }
            public void SetupMovement(List<Vector3> positions) {
                if (isDisabled || tc == null || tc.killed || tc.IsUnloading || npc.IsKilled() || npc.IsDead() || npc.Health() <= 0) {
                    return;
                }
                this.positions = positions;
                InvokeRepeating(TryToRoam, 0f, 7.5f);
                InvokeRepeating(TryToAttack, 1f, 1f);
            }
            private void TryToRoam() {
                if (isDisabled) {
                    return;
                }
                if (Settings.KillUnderwater && npc.playerCollider != null && npc.IsSwimming()) {
                    npc.SafelyKill();
                    return;
                }
                if (ValidTarget) {
                    return;
                }
                if (IsStuck()) {
                    Warp();
                    Navigator.stuckTimer = 0f;
                }
                CurrentSpeed = BaseNavigator.NavigationSpeed.Normal;
                SetDestination();
            }
            private bool IsStuck() => false;
            //InRange(npc.transform.position, Navigator.stuckCheckPosition, Navigator.StuckDistance);
            public void Warp() {
                if (Time.time < lastWarpTime) {
                    return;
                }
                lastWarpTime = Time.time + 1f;
                DestinationOverride = GetRandomRoamPosition();
                Navigator.Warp(DestinationOverride);
            }
            private void UseFlameThrower() {
                if (flameThrower.ammo < flameThrower.maxAmmo * 0.25) {
                    flameThrower.SetFlameState(false);
                    flameThrower.ServerReload();
                    return;
                }
                npc.triggerEndTime = Time.time + attackCooldown;
                flameThrower.SetFlameState(true);
                flameThrower.Invoke(() => flameThrower.SetFlameState(false), 2f);
            }
            private void UseWaterGun() {
                if (Physics.Raycast(npc.eyes.BodyRay(), out var hit, 10f, 1218652417)) {
                    WaterBall.DoSplash(hit.point, 2f, ItemManager.FindItemDefinition("water"), 10);
                    DamageUtil.RadiusDamage(npc, liquidWeapon.LookupPrefab(), hit.point, 0.15f, 0.15f, new(), 131072, true);
                }
            }
            private void UseChainsaw() {
                AttackEntity.TopUpAmmo();
                AttackEntity.ServerUse();
                AttackTarget.Hurt(10f * AttackEntity.npcDamageScale, DamageType.Bleeding, npc);
            }
            private void MeleeAttack() {
                if (baseMelee.IsNull()) {
                    return;
                }
                if (AttackEntity is Chainsaw) {
                    UseChainsaw();
                    return;
                }
                Vector3 position = AttackPosition;
                AttackEntity.StartAttackCooldown(AttackEntity.repeatDelay * 2f);
                npc.SignalBroadcast(BaseEntity.Signal.Attack, string.Empty, null);
                if (baseMelee.swingEffect.isValid) {
                    Effect.server.Run(baseMelee.swingEffect.resourcePath, position, Vector3.forward, npc.Connection, false);
                }
                HitInfo hitInfo = new() {
                    damageTypes = new(), DidHit = true, Initiator = npc, HitEntity = AttackTarget, HitPositionWorld = position, HitPositionLocal = AttackTransform.InverseTransformPoint(position), HitNormalWorld = npc.eyes.BodyForward(), HitMaterial = StringPool.Get("Flesh"), PointStart = ServerPosition, PointEnd = position, Weapon = AttackEntity, WeaponPrefab = AttackEntity
                }
                ;
                hitInfo.damageTypes.Set(DamageType.Slash, baseMelee.TotalDamage() * AttackEntity.npcDamageScale);
                Effect.server.ImpactEffect(hitInfo);
                AttackTarget.OnAttacked(hitInfo);
            }
            private bool CanConverge(global : : HumanNPC other) {
                if (ValidTarget || other.IsKilled() || other.IsDead()) return false;
                return IsInTargetRange(other.transform.position);
            }
            private bool CanLeave(Vector3 destination) {
                return Settings.CanLeave || IsInLeaveRange(destination);
            }
            private bool CanSeeTarget(BasePlayer target) {
                if (Navigator.CurrentNavigationType == BaseNavigator.NavigationType.None && (attackType == AttackType.FlameThrower || attackType == AttackType.Melee)) {
                    return true;
                }
                if (ServerPosition.Distance(target.ServerPosition) < 10f || Senses.Memory.IsLOS(target)) {
                    return true;
                }
                nextAttackTime = Time.realtimeSinceStartup + 1f;
                return false;
            }
            public bool CanRoam(Vector3 destination) {
                return destination == DestinationOverride && IsInSenseRange(destination);
            }
            private bool CanShoot() {
                if (attackType == AttackType.None) {
                    return false;
                }
                return true;
            }
            public BasePlayer GetBestTarget() {
                if (npc.IsWounded()) {
                    return null;
                }
                float delta = -1f;
                BasePlayer target = null;
                foreach (var player in Senses.Memory.Targets.OfType<BasePlayer>()) {
                    if (ShouldForgetTarget(player) || !player.IsHuman() && !Options.NPC.TargetNpcs) continue;
                    float dist = player.transform.position.Distance(npc.transform.position);
                    float rangeDelta = 1f - Mathf.InverseLerp(1f, SenseRange, dist);
                    rangeDelta += (CanSeeTarget(player) ? 2f : 0f);
                    if (rangeDelta <= delta) continue;
                    target = player;
                    delta = rangeDelta;
                }
                return target;
            }
            private Vector3 GetRandomRoamPosition() {
                return positions.GetRandom();
            }
            private bool IsAttackOnCooldown() {
                if (attackType == AttackType.None || Time.realtimeSinceStartup < nextAttackTime) {
                    return true;
                }
                if (attackCooldown > 0f) {
                    nextAttackTime = Time.realtimeSinceStartup + attackCooldown;
                }
                return false;
            }
            private bool IsInAttackRange(float range = 0f) {
                return InRange(ServerPosition, AttackPosition, range == 0f ? attackRange : range);
            }
            private bool IsInHomeRange() {
                return InRange(ServerPosition, tc.containerPos, Mathf.Max(tc.Radius, TargetLostRange));
            }
            private bool IsInLeaveRange(Vector3 destination) {
                return InRange(tc.containerPos, destination, tc.Radius);
            }
            private bool IsInReachableRange() {
                if (AttackPosition.y - ServerPosition.y > attackRange) {
                    return false;
                }
                return attackType != AttackType.Melee || InRange(AttackPosition, ServerPosition, 15f);
            }
            private bool IsInSenseRange(Vector3 destination) {
                return InRange2D(tc.containerPos, destination, SenseRange);
            }
            private bool IsInTargetRange(Vector3 destination) {
                return InRange2D(tc.containerPos, destination, TargetLostRange);
            }
            private bool ShouldForgetTarget(BasePlayer target) {
                return target.IsKilled() || target.health <= 0f || target.limitNetworking || target.IsDead() || target.skinID == 14922524 || !IsInTargetRange(target.transform.position);
            }
        }
        private class GuidanceSystem : FacepunchBehaviour {
            private TimedExplosive missile;
            private ServerProjectile projectile;
            private BaseEntity target;
            private Vector3 launchPos;
            private List<ulong> newmans = new();
            internal DangerousTreasures Instance;
            internal Configuration config;
            internal DifficultyLevel Options;
            private void Awake() {
                missile = GetComponent<TimedExplosive>();
                projectile = missile.GetComponent<ServerProjectile>();
                launchPos = missile.transform.position;
                launchPos.y = TerrainMeta.HeightMap.GetHeight(launchPos);
                projectile.gravityModifier = 0f;
                projectile.speed = 0.1f;
                projectile.InitializeVelocity(Vector3.up);
                missile.explosionRadius = 0f;
                missile.damageTypes = new();
                // no damage
            }
            public void SetTarget(BaseEntity target) {
                this.target = target;
            }
            public void Launch(float targettingTime) {
                missile.timerAmountMin = Options.MissileLauncher.Lifetime;
                missile.timerAmountMax = Options.MissileLauncher.Lifetime;
                missile.Spawn();
                Instance.timer.Once(targettingTime, () => {
                    if (missile.IsKilled()) return;
                    using var list = Pool.Get<PooledList<BasePlayer>>();
                    using var players = FindEntitiesOfType<BasePlayer>(launchPos, Options.Event.Radius + Options.MissileLauncher.Distance, Layers.Mask.Player_Server);
                    for (int i = 0; i < players.Count; i++) {
                        var player = players[i];
                        if (player.IsKilled() || !player.IsHuman() || !player.CanInteract()) continue;
                        if (Options.MissileLauncher.IgnoreFlying && player.IsFlying) continue;
                        if (newmans.Contains(player.userID) || Instance.newmanProtections.Contains(player.userID)) continue;
                        list.Add(player);
                        // acquire a player target
                    }
                    if (list.Count > 0) {
                        target = list.GetRandom();
                        // pick a random player
                    }
                    else if (!Options.MissileLauncher.TargetChest) {
                        missile.SafelyKill();
                        return;
                    }
                    projectile.speed = config.Rocket.Speed * 2f;
                    InvokeRepeating(GuideMissile, 0.1f, 0.1f);
                }
                );
            }
            public void Exclude(List<ulong> newmans) {
                if (newmans != null && newmans.Count > 0) {
                    this.newmans = newmans.ToList();
                }
            }
            private void GuideMissile() {
                if (target == null) return;
                if (target.IsDestroyed) {
                    missile.SafelyKill();
                    return;
                }
                if (missile.IsKilled() || projectile == null) {
                    Destroy(this);
                    return;
                }
                if (InRange(target.transform.position, missile.transform.position, 1f)) {
                    missile.Explode();
                    return;
                }
                var direction = (target.transform.position - missile.transform.position) + Vector3.down;
                // direction to guide the missile
                projectile.InitializeVelocity(direction);
                // guide the missile to the target's position
            }
            private void OnDestroy() {
                try {
                    CancelInvoke();
                }
                catch {
                }
                Destroy(this);
            }
        }
        public class TreasureChest : FacepunchBehaviour {
            internal Dictionary<ulong, HumanoidBrain> HumanoidBrains;
            internal DangerousTreasures Instance;
            internal ulong userid;
            internal GameObject go;
            internal StorageContainer container;
            internal Vector3 containerPos;
            internal Vector3 lastFirePos;
            internal int npcMaxAmountMurderers;
            internal int npcMaxAmountScientists;
            internal int npcSpawnedAmount;
            internal int countdownTime;
            internal bool started;
            internal bool opened;
            internal bool firstEntered;
            internal bool markerCreated;
            internal bool killed;
            internal bool IsUnloading;
            internal bool requireAllNpcsDie;
            internal bool whenNpcsDie;
            internal float claimTime;
            internal float _radius;
            internal long _unlockTime;
            internal NetworkableId uid;
            private Dictionary<string, List<string>> npcKits = Pool.Get<Dictionary<string, List<string>>>();
            private Dictionary<ulong, float> fireticks = Pool.Get<Dictionary<ulong, float>>();
            private List<FireBall> fireballs = Pool.Get<List<FireBall>>();
            private List<ulong> newmans = Pool.Get<List<ulong>>();
            private List<ulong> traitors = Pool.Get<List<ulong>>();
            private List<ulong> protects = Pool.Get<List<ulong>>();
            private List<ulong> players = Pool.Get<List<ulong>>();
            private List<TimedExplosive> missiles = Pool.Get<List<TimedExplosive>>();
            private List<int> times = Pool.Get<List<int>>();
            private List<SphereE
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху