C#:
using System.Collections.Generic;
using System.Collections;
using Oxide.Core.Configuration;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using UnityEngine;
using System.Linq;
using Oxide.Core;
using System;
using Oxide.Game.Rust.Cui;
using UnityEngine.SceneManagement;
using System.Text.RegularExpressions;
using Color = UnityEngine.Color;
using UnityEngine.AI;
using Facepunch;
using Facepunch.Utility;
using VLB;
using Rust;
using System.Reflection;
using ProtoBuf;
using Newtonsoft.Json.Linq;
using Rust.Ai;
using System.Globalization;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins {
[Info("AirField event", "Ts3Hosting", "1.0.27", ResourceId = 31)]
[Description("Cargo Plane AirField Event")]
public class AirFieldEvent : RustPlugin {
[PluginReference]
Plugin Kits;
private static List<NpcAIcontroler> _AllNpcAI = new List<NpcAIcontroler>();
public static AirFieldEvent _;
private const string CARGOPLANE = "assets/prefabs/npc/cargo plane/cargo_plane.prefab";
readonly Dictionary<int, Timer> CheckEvent = new Dictionary<int, Timer>();
static System.Random random = new System.Random();
MonumentInfo monumentInfo;
private Vector3 airfieldLocation;
private Quaternion airfieldQuaternion;
public List<BaseEntity> _allNPC = new List<BaseEntity>();
public List<AirFieldNPC> allScientists = new List<AirFieldNPC>();
private List<HackableLockedCrate> eventCrate = new List<HackableLockedCrate>();
private bool eventRunning;
public radZonesEvent towerMain;
public radZonesEvent towerOne;
public radZonesEvent towerTwo;
public radZonesEvent towerThree;
public radZonesEvent towerFour;
private bool isStrikePlane(CargoPlane plane) => plane.GetComponent<cargoPlainMono>();
private bool isEventPlane(CargoPlane plane) => plane.GetComponent<cargoPlainMono>();
private static bool debug = true;
private new void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["NoPerm"]
= "<color=#ce422b>You can not use this command.</color>", ["StartingEvent"] = "<color=#ce422b>You spawned event crate at Airfield.</color>", ["AlreadyCrate"] = "<color=#ce422b>There is a crate already at Airfield</color>", ["EventRunning"] = "<color=#ce422b>There is a event already running.</color>",
}
, this);
}
#region Config
private ConfigData configData;
class ConfigData {
[JsonProperty(PropertyName = "Settings")]
public Settings settings {
get;
set;
}
[JsonProperty(PropertyName = "HumanNPC Settings")]
public SettingsNpc settingsNpc {
get;
set;
}
public class Settings {
public string PermissionUse {
get;
set;
}
public float StartDistance {
get;
set;
}
public bool SpawnScientists {
get;
set;
}
public bool RadTowers {
get;
set;
}
public float MaxRads {
get;
set;
}
public bool NoBradleyCrates {
get;
set;
}
}
public class SettingsNpc {
public List<TheData> loadOut {
get;
set;
}
}
public Oxide.Core.VersionNumber Version {
get;
set;
}
}
protected override void LoadConfig() {
_ = this;
base.LoadConfig();
configData = Config.ReadObject<ConfigData>();
if (configData.Version < Version) UpdateConfigValues();
Config.WriteObject(configData, true);
}
protected override void LoadDefaultConfig() => configData = GetBaseConfig();
private ConfigData GetBaseConfig() {
return new ConfigData {
settings = new ConfigData.Settings {
PermissionUse = "airfieldevent.admin", StartDistance = 2000f, SpawnScientists = true, RadTowers = true, MaxRads = 50.0f, NoBradleyCrates = false
}
, settingsNpc = new ConfigData.SettingsNpc {
loadOut = new List<TheData>()
}
, Version = Version
}
;
}
protected override void SaveConfig() => Config.WriteObject(configData, true);
private void UpdateConfigValues() {
PrintWarning("Config update detected! Updating config values...");
ConfigData baseConfig = GetBaseConfig();
if (configData.Version < new VersionNumber(1, 0, 1)) configData = baseConfig;
configData.Version = Version;
PrintWarning("Config update completed!");
}
#endregion
public class TheData {
public float roamRange;
public float health;
public float Speed;
public float agroRange;
public int totalToSpawn;
public bool radio;
public List<string> kits;
}
void Init() {
permission.RegisterPermission(configData.settings.PermissionUse, this);
}
private void OnServerInitialized() {
bool hasAirfield = false;
foreach (var monument in UnityEngine.Object.FindObjectsOfType<MonumentInfo>()) {
var monumentName = GetMonumentName(monument);
if (monumentName == null || !monumentName.Contains("airfield")) continue;
hasAirfield = true;
monumentInfo = monument;
airfieldQuaternion = Quaternion.Euler(monument.transform.localEulerAngles.x, monument.transform.localEulerAngles.y, monument.transform.localEulerAngles.z);
airfieldLocation = monument.transform.position;
}
if (!hasAirfield) {
PrintWarning("No AirField found on your map PLUGIN UNLOADED.");
covalence.Server.Command("o.unload CargoPlaneEvent");
return;
}
if (configData.settingsNpc.loadOut.Count <= 0) {
configData.settingsNpc.loadOut.Add(new TheData {
roamRange = 30, health = 100, Speed = 2.4f, agroRange = 100, totalToSpawn = 5, radio = false, kits = new List<string>()
}
);
SaveConfig();
}
booted = true;
}
public bool booted;
private void Unload() {
foreach (var Controler in UnityEngine.Object.FindObjectsOfType<radZonesEvent>()) {
UnityEngine.Object.Destroy(Controler);
}
cargoPlainMono[] planes = UnityEngine.Object.FindObjectsOfType<cargoPlainMono>();
for (int i = 0; i < planes?.Length; i++) {
if (planes[i] == null) continue;
UnityEngine.Object.Destroy(planes[i]);
}
foreach (BaseEntity entity in _allNPC.ToList()) {
entity?.Kill();
}
runeventEnd();
}
#region Radation Zone Trigger
public class radZonesEvent : MonoBehaviour {
private Rigidbody rigidbody;
private Collider collider;
private Bounds bounds;
private BoxCollider boxCollider;
public List<BasePlayer> radPlayer = new List<BasePlayer>();
private void Awake() {
//transform.rotation = Quaternion.Euler(0f, _instance.configData.eventSettings.RedZoneRotation, 0f);
if (rigidbody != null) DestroyImmediate(rigidbody);
gameObject.layer = (int)Layer.Reserved1;
gameObject.name = "Trigger";
rigidbody = gameObject.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
rigidbody.detectCollisions = true;
rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
boxCollider = gameObject.GetComponent<BoxCollider>();
}
public void setUpPosition(Vector3 position, Vector3 size) {
transform.position = position;
if (position != Vector3.zero) {
if (boxCollider == null) {
boxCollider = gameObject.AddComponent<BoxCollider>();
boxCollider.isTrigger = true;
}
boxCollider.size = size;
bounds = boxCollider.bounds;
collider = boxCollider;
}
//foreach (BasePlayer player in BasePlayer.activePlayerList.ToList())
//_.drawZones(player, position, 0f, boxCollider.size / 2);
InvokeRepeating("radPlayers", 0.5f, 0.6f);
}
private void radPlayers() {
foreach (BasePlayer player in radPlayer.ToList()) {
if (player == null || player.IsDead() || Vector3.Distance(transform.position, player.transform.position) > 50f) {
radPlayer.Remove(player);
}
else if (player.metabolism.radiation_level.value < _.configData.settings.MaxRads || _.configData.settings.MaxRads == 0) {
player.metabolism.radiation_level.value += 1f;
player.metabolism.radiation_poison.value += 1f;
player.UpdateRadiation(player.metabolism.radiation_level.value);
player.SendNetworkUpdate();
}
}
}
void OnDestroy() => UnityEngine.GameObject.Destroy(gameObject);
public void Destory() {
if (rigidbody != null) DestroyImmediate(rigidbody);
if (boxCollider != null) DestroyImmediate(boxCollider);
UnityEngine.GameObject.Destroy(gameObject);
}
private void OnTriggerEnter(Collider col) {
BaseEntity baseEntity = col?.ToBaseEntity();
if (!baseEntity.IsValid() || !baseEntity is BasePlayer) return;
BasePlayer thePlayer = baseEntity as BasePlayer;
if (thePlayer == null || radPlayer.Contains(thePlayer)) return;
radPlayer.Add(thePlayer);
}
private void OnTriggerExit(Collider col) {
BaseEntity baseEntity = col?.ToBaseEntity();
if (!baseEntity.IsValid() || !baseEntity is BasePlayer) return;
BasePlayer thePlayer = baseEntity as BasePlayer;
if (thePlayer == null || !radPlayer.Contains(thePlayer)) return;
radPlayer.Remove(thePlayer);
}
}
#endregion
#region Cargo Plane
private class cargoPlainMono : MonoBehaviour {
private CargoPlane plane;
private BradleyAPC bradly;
private bool islanding;
private bool landed;
private bool eventRunning;
private Transform tr;
private MonumentInfo monument = _.monumentInfo;
private Vector3 startPos;
public Vector3 endPos;
public Vector3 endPosPrepLand;
private Vector3 startPosLand;
public Vector3 endPosLand;
public Vector3 endPosstart;
public Vector3 endPosEvent;
public Vector3 dropHeavys = Vector3.zero;
public Vector3 dropTank = Vector3.zero;
private Vector3 bradleySpawn;
private bool takeOFf;
private bool isEnding;
private float currentSpeed;
private Vector3 baseEulerAngles;
private float timeTaken;
private bool radSet;
private string fireCannonEffect = "assets/prefabs/npc/m2bradley/effects/maincannonattack.prefab";
readonly Dictionary<Vector3, Timer> rockettimer = new Dictionary<Vector3, Timer>();
private Vector3 tower0;
private Vector3 tower1;
private Vector3 tower2;
private Vector3 tower3;
private Vector3 tower4;
private void Awake() {
plane = GetComponent<CargoPlane>();
plane.enabled = false;
tr = plane.transform;
//138.1356f, 25.5209f, -42.6026f
startPos = monument.transform.TransformPoint(new Vector3(1714.0540f, 93.2331f, -139.9399f));
endPos = monument.transform.TransformPoint(new Vector3(714.0540f, 93.2331f, -39.9399f));
endPosPrepLand = monument.transform.TransformPoint(new Vector3(138.1356f, 0.3f, -42.6026f));
endPosEvent = monument.transform.TransformPoint(new Vector3(-19.1976f, 0.5572f, -43.5018f));
bradleySpawn = monument.transform.TransformPoint(new Vector3(81.6523f, 1.0561f, -43.6350f));
baseEulerAngles = endPosPrepLand;
tower0 = monument.transform.TransformPoint(new Vector3(-42.9318f, 25.9105f, -83.7037f));
tower1 = monument.transform.TransformPoint(new Vector3(107.5858f, 22.3148f, -101.7767f));
tower2 = monument.transform.TransformPoint(new Vector3(119.1027f, 22.0004f, 21.3733f));
tower3 = monument.transform.TransformPoint(new Vector3(-109.3187f, 22.1835f, 68.3177f));
tower4 = monument.transform.TransformPoint(new Vector3(-106.3504f, 19.1489f, -108.7641f));
gameObject.layer = (int)Layer.Reserved2;
gameObject.name = "EventPlane";
ColliderAdd();
currentSpeed = 35f;
_.NextTick(() => {
setupPlane();
}
);
}
public void FireRocket(Vector3 hitPos) {
Effect.server.Run(fireCannonEffect, plane, 0u, Vector3.zero, Vector3.zero, null, false);
Vector3 launchPos = plane.transform.position + plane.transform.forward * 1;
Vector3 newTarget = hitPos;
BaseEntity rocket = GameManager.server.CreateEntity("assets/prefabs/ammo/rocket/rocket_hv.prefab", launchPos, new Quaternion(), true);
TimedExplosive rocketExplosion = rocket.GetComponent<TimedExplosive>();
ServerProjectile rocketProjectile = rocket.GetComponent<ServerProjectile>();
rocketProjectile.speed = 30;
rocketProjectile.gravityModifier = 0;
rocketExplosion.timerAmountMin = 60;
rocketExplosion.timerAmountMax = 60;
Vector3 newDirection = (newTarget - launchPos);
rocketProjectile.InitializeVelocity(newDirection * 2);
rocket.Spawn();
rockettimer[hitPos] = _.timer.Every(0.5f, () => {
if (rocket == null) {
if (hitPos == tower1) {
_.towerOne = new GameObject().AddComponent<radZonesEvent>();
_.towerOne.setUpPosition(hitPos, new Vector3(19f, 20f, 19f));
}
else if (hitPos == tower2) {
_.towerTwo = new GameObject().AddComponent<radZonesEvent>();
_.towerTwo.setUpPosition(hitPos, new Vector3(19f, 18f, 19f));
}
else if (hitPos == tower3) {
_.towerThree = new GameObject().AddComponent<radZonesEvent>();
_.towerThree.setUpPosition(hitPos, new Vector3(19f, 20f, 19f));
}
else if (hitPos == tower4) {
_.towerFour = new GameObject().AddComponent<radZonesEvent>();
_.towerFour.setUpPosition(hitPos, new Vector3(19f, 20f, 19f));
}
rockettimer[hitPos].Destroy();
}
}
);
}
private void setRadZones() {
FireRocket(tower1);
_.timer.Once(10, () => {
FireRocket(tower2);
}
);
_.timer.Once(3, () => {
FireRocket(tower3);
}
);
_.timer.Once(11, () => {
FireRocket(tower4);
}
);
}
private void setupPlane() {
float x = TerrainMeta.Size.x;
float y;
startPos.y = (TerrainMeta.HighestPoint.y * 1.0f);
tr.rotation = Quaternion.LookRotation(endPos - startPos);
plane.transform.position = startPos;
plane.transform.position = tr.position + plane.transform.forward * -_.configData.settings.StartDistance;
}
private void ColliderAdd() {
Rigidbody rigidbody = gameObject.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
rigidbody.detectCollisions = true;
rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
BoxCollider collider = gameObject.AddComponent<BoxCollider>();
collider.isTrigger = true;
collider.size = new Vector3(50, 10, 50);
collider.transform.localPosition = Vector3.up * 6;
}
private void Update() {
if (!islanding && Vector3.Distance(tr.position, endPos) <= 15) {
baseEulerAngles = tr.eulerAngles;
islanding = true;
if (!radSet && _.configData.settings.RadTowers) setRadZones();
}
if (islanding) {
if (!landed && Vector3.Distance(tr.position, endPosPrepLand) <= 5) {
islanding = false;
landed = true;
return;
}
timeTaken = timeTaken + Time.deltaTime;
float delta = Mathf.InverseLerp(0, 20, timeTaken);
if (delta < 1) {
// currentSpeed = currentSpeed - Mathf.Lerp(0, 100, delta);
Vector3 direction = baseEulerAngles;
float yaw = Mathf.Lerp(0f, 25f, delta * 2f);
float turn = Mathf.Lerp(0f, 5f, delta * 2f);
direction.x -= yaw;
direction.y -= turn;
tr.eulerAngles = direction;
}
tr.position = Vector3.MoveTowards(tr.position, endPosPrepLand, currentSpeed * UnityEngine.Time.deltaTime);
}
else if (!landed) {
tr.position = Vector3.MoveTowards(tr.position, endPos, currentSpeed * UnityEngine.Time.deltaTime);
}
else if (landed && !eventRunning) {
if (!takeOFf && bradly == null && Vector3.Distance(tr.position, bradleySpawn) <= 1.2f) {
Vector3 dropOff = tr.position + plane.transform.forward * -15f;
dropOff.y = bradleySpawn.y + 1f;
spawnBradley(dropOff);
}
if (Vector3.Distance(tr.position, endPosEvent) <= 0.1) {
eventRunning = true;
timeTaken = 0;
baseEulerAngles = tr.eulerAngles;
takeOFf = true;
}
tr.position = Vector3.MoveTowards(tr.position, endPosEvent, currentSpeed * UnityEngine.Time.deltaTime);
}
else if (takeOFf) {
if (!isEnding) {
isEnding = true;
_.timer.Once(180, () => {
if (this != null) UnityEngine.GameObject.Destroy(gameObject);
}
);
}
timeTaken = timeTaken + Time.deltaTime;
float delta = Mathf.InverseLerp(0, 20, timeTaken);
if (delta < 1) {
Vector3 direction = baseEulerAngles;
float yaw = Mathf.Lerp(0f, 15f, delta * 2f);
direction.x -= yaw;
tr.eulerAngles = direction;
}
if (currentSpeed < 45f) currentSpeed = currentSpeed + 0.02f;
Vector3 enddirection = tr.position + tr.forward * 30f;
if (enddirection is Vector3) {
if (tr.position.y < 1200f) enddirection.y = tr.position.y + 10f;
tr.position = Vector3.MoveTowards(tr.position, enddirection, currentSpeed * UnityEngine.Time.deltaTime);
}
}
}
private void spawnBradley(Vector3 position) {
bradly = GameManager.server.CreateEntity("assets/prefabs/npc/m2bradley/bradleyapc.prefab", position) as BradleyAPC;
bradly.enableSaving = false;
bradly.transform.rotation = tr.rotation;
bradly.Spawn();
_._allNPC.Add(bradly);
BradlyAIPlane Brad = bradly.gameObject.AddComponent<BradlyAIPlane>();
if (_.configData.settings.NoBradleyCrates) bradly.maxCratesToSpawn = 0;
}
private void OnDestroy() {
if (plane != null) plane?.Kill();
}
}
#endregion
#region Brwdley controler
public class BradlyAIPlane : MonoBehaviour {
public BradleyAPC bradly;
public BasePlayer player;
public MonumentInfo monument = _.monumentInfo;
public List<Vector3> Path = new List<Vector3>();
private Coroutine QueuedRoutine;
public bool stopped;
public float lastSeenTime = 0f;
public int currentPathIndex;
public DateTime Active;
private Vector3 aimVector = Vector3.forward;
private Vector3 aimVectorTop = Vector3.forward;
private int oldpath = 0;
private bool IsAiming;
private bool okGo;
private float moveForce = 650.0f;
private bool spawnSupport;
private Coroutine QueuedRoutineSpawn;
private void Awake() {
bradly = GetComponent<BradleyAPC>();
Active = DateTime.Now.AddSeconds(2);
_.NextTick(() => {
MakePath();
}
);
moveForce = 2650f;
bradly.moveForceMax = moveForce;
}
private void OnDestroy() {
if (QueuedRoutineSpawn != null) {
ServerMgr.Instance.StopCoroutine(QueuedRoutineSpawn);
QueuedRoutineSpawn = null;
}
if (QueuedRoutine != null) {
ServerMgr.Instance.StopCoroutine(QueuedRoutine);
QueuedRoutine = null;
}
}
void Relocate() {
if (bradly.targetList.Count <= 0) {
aimWeaponAt();
StartMoving();
CancelInvoke("Relocate");
return;
}
}
private void MakePath() {
Path.Clear();
Path.Add(monument.transform.TransformPoint(new Vector3(-70.1203f, 0.5f, -43.5743f)));
Path.Add(monument.transform.TransformPoint(new Vector3(-83.3062f, 0.5f, -52.4218f)));
Path.Add(monument.transform.TransformPoint(new Vector3(-85.1310f, 0.2761f, -64.1430f)));
Path.Add(monument.transform.TransformPoint(new Vector3(-71.2152f, 0.5f, -74.1124f)));
Path.Add(monument.transform.TransformPoint(new Vector3(-56.8051f, 0.5f, -55.6783f)));
bradly.currentPath = Path;
bradly.currentPathIndex = 0;
bradly.pathLooping = true;
bradly.SendNetworkUpdateImmediate();
}
private void StopMoving() {
currentPathIndex = bradly.currentPathIndex;
bradly.pathLooping = false;
bradly.ClearPath();
}
void StartMoving() {
if (Path.Count <= 0) MakePath();
bradly.currentPath = Path;
bradly.currentPathIndex = currentPathIndex;
bradly.pathLooping = true;
bradly.moveForceMax = moveForce;
stopped = false;
}
private IEnumerator updateAim() {
while (!stopped) {
aimWeaponAt();
yield return new WaitForSeconds(4);
}
if (QueuedRoutine != null && stopped) InvokeHandler.Instance.StopCoroutine(QueuedRoutine);
QueuedRoutine = null;
}
private void spawnScientists() {
if (QueuedRoutineSpawn != null) return;
TheData dataLoadOut = null;
if (_.configData.settingsNpc.loadOut.Count == 1) dataLoadOut = _.configData.settingsNpc.loadOut[0];
else dataLoadOut = _.configData.settingsNpc.loadOut[UnityEngine.Random.Range(0, _.configData.settingsNpc.loadOut.Count - 1)];
if (dataLoadOut != null && QueuedRoutineSpawn == null) QueuedRoutineSpawn = ServerMgr.Instance.StartCoroutine(SpawnAllScientists(dataLoadOut.totalToSpawn, dataLoadOut));
}
private IEnumerator SpawnAllScientists(int total, TheData dataLoadOut) {
while (total > 0) {
total--;
_.SpawnScientist(bradly.transform.position, dataLoadOut, _.monumentInfo.transform.TransformPoint(new Vector3(-71.1748f, 0.3189f, -62.0878f)));
yield return CoroutineEx.waitForSeconds(0.2f);
}
if (QueuedRoutineSpawn != null) {
ServerMgr.Instance.StopCoroutine(QueuedRoutineSpawn);
QueuedRoutineSpawn = null;
}
}
private void Update() {
if (!spawnSupport && bradly.currentPathIndex == 1 && bradly.moveForceMax != 650f) {
spawnSupport = true;
moveForce = 650f;
bradly.moveForceMax = moveForce;
stopped = true;
StopMoving();
if (_.configData.settings.SpawnScientists) spawnScientists();
_.timer.Once(10, () => {
if (this != null) okGo = true;
stopped = false;
StartMoving();
}
);
}
if (bradly == null || !okGo) return;
if (monument == null) return;
if (!stopped && bradly.targetList.Count >= 1) {
stopped = true;
StopMoving();
float delay = random.Next(2, 6);
InvokeRepeating("Relocate", delay, delay);
return;
}
//Ajust Aim
if (QueuedRoutine == null && !stopped) {
QueuedRoutine = InvokeHandler.Instance.StartCoroutine(updateAim());
}
//Fix if loses path
if (!stopped && Active < DateTime.Now && bradly.currentPath != Path && bradly.targetList.Count <= 0) {
StartMoving();
}
}
//SetAim
void aimWeaponAt() {
bradly.desiredAimVector = bradly.topTurretAimVector;
bradly.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
IsAiming = false;
}
private void OnCollisionEnter(Collision collision) {
GameObject gObject = collision.gameObject;
if (gObject == null) return;
ResourceEntity resource = gObject.GetComponentInParent<ResourceEntity>();
if (resource != null) {
resource.Kill(BaseNetworkable.DestroyMode.None);
return;
}
ModularCar car = gObject.GetComponentInParent<ModularCar>();
if (car != null) {
Rigidbody rBody = car.GetComponent<Rigidbody>();
if (rBody != null) {
if (rBody.IsSleeping()) rBody.WakeUp();
var nullHit = new HitInfo(bradly, car, Rust.DamageType.Explosion, 100, car.transform.position);
nullHit.damageTypes.Add(Rust.DamageType.AntiVehicle, 50f);
car.Hurt(nullHit);
}
return;
}
}
}
#endregion
#region spawningNPC
internal AirFieldNPC SpawnScientist(Vector3 pos, TheData loadOut, Vector3 center) {
pos.y = TerrainMeta.HeightMap.GetHeight(pos);
object position = FindPointOnNavmesh(pos, 10f);
if (position is Vector3 && (Vector3)position != Vector3.zero) {
AirFieldNPC scientistNPC = InstantiateEntity((Vector3)position, Quaternion.Euler(0, 0, 0));
if (scientistNPC == null) return null;
scientistNPC.enableSaving = false;
scientistNPC.Spawn();
_allNPC.Add(scientistNPC);
allScientists.Add(scientistNPC);
scientistNPC.gameObject.SetActive(true);
NextTick(() => {
if (scientistNPC == null) return;
scientistNPC.InitNewSettings(center, loadOut.health, 20f, loadOut.agroRange);
scientistNPC.setUpGear(loadOut.kits.GetRandom());
}
);
NpcAIcontroler controler = scientistNPC.GetOrAddComponent<NpcAIcontroler>();
if (scientistNPC != null) return scientistNPC;
}
return null;
}
private static AirFieldNPC InstantiateEntity(Vector3 position, Quaternion rotation) {
GameObject gameObject = Instantiate.GameObject(GameManager.server.FindPrefab("assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_any.prefab"), position, Quaternion.identity);
gameObject.name = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_any.prefab";
gameObject.SetActive(false);
ScientistNPC scientistNPC = gameObject.GetComponent<ScientistNPC>();
ScientistBrain defaultBrain = gameObject.GetComponent<ScientistBrain>();
defaultBrain._baseEntity = scientistNPC;
AirFieldNPC component = gameObject.AddComponent<AirFieldNPC>();
NpcRaiderBrain brains = gameObject.AddComponent<NpcRaiderBrain>();
brains.Pet = false;
brains.AllowedToSleep = false;
CopySerializeableFields<NPCPlayer>(scientistNPC, component);
brains._baseEntity = component;
UnityEngine.Object.DestroyImmediate(defaultBrain, true);
UnityEngine.Object.DestroyImmediate(scientistNPC, true);
UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(gameObject, Rust.Server.EntityScene);
UnityEngine.Object.Destroy(gameObject.GetComponent<Spawnable>());
return component;
}
#region navMesh
private static NavMeshHit navmeshHit;
private static RaycastHit raycastHit;
private static Collider[] _buffer = new Collider[256];
private const int WORLD_LAYER = 65536;
internal static object FindPointOnNavmesh(Vector3 targetPosition, float maxDistance = 4f) {
for (int i = 0; i < 10; i++) {
Vector3 position = i == 0 ? targetPosition : targetPosition + (UnityEngine.Random.onUnitSphere * maxDistance);
if (NavMesh.SamplePosition(position, out navmeshHit, maxDistance, 1)) {
if (IsInRockPrefab2(navmeshHit.position)) continue;
if (IsNearWorldCollider(navmeshHit.position)) continue;
return navmeshHit.position;
}
}
return null;
}
internal static bool IsInRockPrefab(Vector3 position) {
Physics.queriesHitBackfaces = true;
bool isInRock = Physics.Raycast(position, Vector3.up, out raycastHit, 20f, WORLD_LAYER, QueryTriggerInteraction.Ignore) && blockedColliders.Any(s => raycastHit.collider?.gameObject?.name.ToLower().Contains(s) ?? false);
Physics.queriesHitBackfaces = false;
return isInRock;
}
internal static bool IsInRockPrefab2(Vector3 position) {
Vector3 p1 = position + new Vector3(0, 20f, 0);
Vector3 p2 = position + new Vector3(0, -2f, 0);
Vector3 diff = p2 - p1;
RaycastHit[] hits;
hits = Physics.RaycastAll(p1, diff, diff.magnitude);
if (hits.Length > 0) {
for (int i = 0; i < hits.Length; i++) {
RaycastHit hit = hits[i];
if (hit.collider != null) {
bool isRock = blockedColliders.Any(s => hit.collider?.gameObject?.name.ToLower().Contains(s) ?? false);
if (isRock) return true;
}
}
}
return false;
}
internal static bool IsNearWorldCollider(Vector3 position) {
Physics.queriesHitBackfaces = true;
int count = Physics.OverlapSphereNonAlloc(position, 2f, _buffer, WORLD_LAYER, QueryTriggerInteraction.Ignore);
Physics.queriesHitBackfaces = false;
int removed = 0;
for (int i = 0; i < count; i++) {
if (acceptedColliders.Any(s => _buffer[i].gameObject.name.Contains(s))) removed++;
}
return count - removed > 0;
}
private static readonly string[] acceptedColliders = new string[] {
"road", "carpark", "rocket_factory", "range", "train_track", "runway", "_grounds", "concrete_slabs", "lighthouse", "cave", "office", "walkways", "sphere", "tunnel", "industrial", "junkyard"
}
;
private static readonly string[] blockedColliders = new string[] {
"rock", "junk", "range", "invisible", "cliff"
}
;
#endregion
private static void CopySerializeableFields<T>(T src, T dst) {
FieldInfo[] srcFields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo field in srcFields) {
object value = field.GetValue(src);
field.SetValue(dst, value);
}
}
public class AirFieldNPC : NPCPlayer, IAISenses, IAIAttack, IThinker {
public int AdditionalLosBlockingLayer;
public LootContainer.LootSpawnSlot[] LootSpawnSlots;
public float aimConeScale = 2f;
public float lastDismountTime;
[NonSerialized]
protected bool lightsOn;
private float nextZoneSearchTime;
private AIInformationZone cachedInfoZone;
private float targetAimedDuration;
private float lastAimSetTime;
private Vector3 aimOverridePosition = Vector3.zero;
public BaseCombatEntity currentTarget {
get;
set;
}
private List<int> _ProjectilesSlot = new List<int>();
private List<int> _MeleWeaponSlot = new List<int>();
public Vector3 HomePosition {
get;
set;
}
public bool isMountedAgent {
get;
set;
}
private float lastTargetTime {
get;
set;
}
private Vector3 lastTargetPosition {
get;
set;
}
public Vector3 lostPosition() => lastTargetPosition;
public bool GoodLastTime() => lastTargetTime > Time.time;
public override float StartHealth() => this.startHealth;
public override float StartMaxHealth() => this.startHealth;
public override float MaxHealth() => this.startHealth;
public NpcRaiderBrain Brain {
get;
private set;
}
public override bool IsLoadBalanced() => true;
public bool HasTarget() => (currentTarget != null);
public override void ServerInit() {
if (NavAgent == null) NavAgent = GetComponent<NavMeshAgent>();
NavAgent.areaMask = 1;
NavAgent.agentTypeID = -1372625422;
GetComponent<BaseNavigator>().DefaultArea = "Walkable";
base.ServerInit();
Brain = this.GetComponent<NpcRaiderBrain>();
AIThinkManager.Add((IThinker)this);
_.NextTick(() => {
if (this == null) return;
InitNewSettings(this.transform.position);
InitMovementSettings();
setupweapons();
}
);
}
public void InitNewSettings(Vector3 home, float health = 100f, float Memory = 20f, float SenseRange = 30f, float LostRange = 250f, float attackRange = 2f, bool isMounted = false) {
_.NextFrame(() => {
if (this == null) return;
if (home == Vector3.zero) HomePosition = this.transform.position;
else HomePosition = home;
this.startHealth = health;
this.InitializeHealth(health, health);
this.health = health;
Brain.Senses.MemoryDuration = Memory;
Brain.AttackRangeMultiplier = attackRange;
Brain.SenseRange = SenseRange;
Brain.TargetLostRange = LostRange;
isMountedAgent = isMounted;
//attackEntity.aiOnlyInRange
}
);
}
public void InitMovementSettings(float Acceleration = 12f, float Speed = 6.0f, float TurnSpeed = 120f, float NormalSpeedFraction = 0.5f, float FastSpeedFraction = 1f, float LowHealthMaxSpeedFraction = 0.9f, float SlowestSpeedFraction = 0.16f, float SlowSpeedFraction = 0.3f, float BestMovementPointMaxDistance = 20f, float MaxRoamDistanceFromHome = 30f, float BestRoamPointMaxDistance = 25f, float BestCoverPointMaxDistance = 5f) {
_.NextFrame(() => {
if (this == null) return;
Brain.Navigator.Acceleration = Acceleration;
Brain.Navigator.Speed = Speed;
Brain.Navigator.TurnSpeed = TurnSpeed;
Brain.Navigator.NormalSpeedFraction = NormalSpeedFraction;
Brain.Navigator.FastSpeedFraction = FastSpeedFraction;
Brain.Navigator.LowHealthMaxSpeedFraction = LowHealthMaxSpeedFraction;
Brain.Navigator.SlowestSpeedFraction = SlowestSpeedFraction;
Brain.Navigator.SlowSpeedFraction = SlowSpeedFraction;
Brain.Navigator.BestMovementPointMaxDistance = BestMovementPointMaxDistance;
Brain.Navigator.MaxRoamDistanceFromHome = MaxRoamDistanceFromHome;
Brain.Navigator.BestRoamPointMaxDistance = BestRoamPointMaxDistance;
Brain.Navigator.BestCoverPointMaxDistance = BestCoverPointMaxDistance;
EquipWeapon();
}
);
}
public void setUpGear(string kitname = "") {
if (!string.IsNullOrEmpty(kitname)) {
this.inventory.Strip();
object success = _.Kits.Call("GetKitInfo", kitname);
if (success == null) {
addDefaultGear();
_.PrintWarning($"Unable to find a kit with name {kitname}?");
}
else {
JObject obj = success as JObject;
JArray items = obj["items"] as JArray;
for (int i = 0; i < items.Count; i++) {
JObject itemObject = items[i] as JObject;
string container = (string)itemObject["container"];
if (container == "wear") ItemManager.CreateByItemID((int)itemObject["itemid"], (int)itemObject["amount"], (ulong)itemObject["skinid"]).MoveToContainer(this.inventory.containerWear, 0);
else if (container == "belt") {
Item item = ItemManager.CreateByItemID((int)itemObject["itemid"], (int)itemObject["amount"], (ulong)itemObject["skinid"]);
item.MoveToContainer(this.inventory.containerBelt, -1, true);
this.inventory.containerBelt.OnChanged();
}
}
setupweapons();
if (_ProjectilesSlot.Count > 0) EquipNewWeapon(_ProjectilesSlot[0]);
else if (_MeleWeaponSlot.Count > 0) EquipNewWeapon(_MeleWeaponSlot[0]);
}
}
else {
addDefaultGear();
EquipWeapon();
setupweapons();
}
}
private void addDefaultGear() {
switch (UnityEngine.Random.Range(0, 7)) {
case 0 : ItemManager.CreateByName("scientistsuit_heavy").MoveToContainer(this.inventory.containerWear);
break;
case 1 : ItemManager.CreateByName("hazmatsuit_scientist_peacekeeper").MoveToContainer(this.inventory.containerWear);
break;
case 2 : ItemManager.CreateByName("hazmatsuit_scientist").MoveToContainer(this.inventory.containerWear);
break;
case 3 : ItemManager.CreateByName("hazmatsuit").MoveToContainer(this.inventory.containerWear);
break;
case 4 : ItemManager.CreateByName("scientistsuit_heavy").MoveToContainer(this.inventory.containerWear);
break;
case 5 : ItemManager.CreateByName("hazmatsuit_scientist_peacekeeper").MoveToContainer(this.inventory.containerWear);
break;
case 6 : ItemManager.CreateByName("hazmatsuit_scientist").MoveToContainer(this.inventory.containerWear);
break;
case 7 : ItemManager.CreateByName("hazmatsuit").MoveToContainer(this.inventory.containerWear);
break;
default : ItemManager.CreateByName("hazmatsuit_scientist").MoveToContainer(this.inventory.containerWear);
break;
}
switch (UnityEngine.Random.Range(0, 9)) {
case 0 : ItemManager.CreateByName("smg.mp5").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 1 : ItemManager.CreateByName("shotgun.spas12").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 2 : ItemManager.CreateByName("rifle.lr300").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 3 : ItemManager.CreateByName("lmg.m249").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 4 : ItemManager.CreateByName("pistol.m92").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 5 : ItemManager.CreateByName("smg.mp5").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 6 : ItemManager.CreateByName("shotgun.spas12").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 7 : ItemManager.CreateByName("rifle.lr300").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 8 : ItemManager.CreateByName("lmg.m249").MoveToContainer(this.inventory.containerBelt, 0);
break;
case 9 : ItemManager.CreateByName("pistol.m92").MoveToContainer(this.inventory.containerBelt, 0);
break;
default : ItemManager.CreateByName("pistol.m92").MoveToContainer(this.inventory.containerBelt, 0);
break;
}
this.inventory.containerBelt.OnChanged();
}
private void setupweapons() {
_ProjectilesSlot = new List<int>();
_MeleWeaponSlot = new List<int>();
foreach (Item slot in inventory.containerBelt.itemList) {
if (slot != null) {
BaseEntity heldEntity = slot.GetHeldEntity();
if (heldEntity != null) {
AttackEntity _attackEntity = heldEntity.GetComponent<AttackEntity>();
if (_attackEntity != null) {
if (_attackEntity is BaseProjectile) {
_ProjectilesSlot.Add(slot.position);
_attackEntity.aiOnlyInRange = false;
}
else _MeleWeaponSlot.Add(slot.position);
}
}
}
}
}
public bool EquipNewWeapon(int slot = 0) {
Item weapon = this.inventory.containerBelt.GetSlot(slot);
if (weapon != null) {
BaseEntity heldEntity = weapon.GetHeldEntity();
if (heldEntity != null) {
AttackEntity _
// ... [Code preview truncated due to length. Full source in attached file] ...