C#:
using System;
using UnityEngine;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using System.Collections.Generic;
using HarmonyLib;
namespace Oxide.Plugins {
[Info("CargoPlaneCrash", "Fruster", "1.4.0")]
[Description("CargoPlaneCrash")]
class CargoPlaneCrash : CovalencePlugin {
private List<Vector3> spawnItems = new List<Vector3>();
private float remainToEvent;
private float remain;
private string prefabstr = "assets/prefabs/npc/cargo plane/cargo_plane.prefab";
private BaseEntity entity;
private Vector3 target = new Vector3(0, 0, 0);
private float mapSize;
private float speed;
private Vector3 direction;
private float crashRadius = 10f;
private bool expMarker;
private bool signalSmoke;
private int cratesAmount;
private int airdropsAmount;
private int fireballsAmount;
private int passengersAmount;
private RaycastHit check;
private LayerMask layerS = LayerMask.GetMask("Construction", "Terrain", "Water", "World");
private string message;
private string kitName;
public static string passengerName = "Passenger";
private Vector3 crashZoneCenter;
private Vector3 crashPosition;
[PluginReference]
Plugin Kits, SimpleLootTable;
private float altitude;
private int lifeTimeExpMarker;
private int lifeTimeCrates;
private int lifeTimeAirdrops;
private bool smokeFlag = false;
private int lifeTimeSignalSmoke;
private string botPrefab = "assets/prefabs/player/player.prefab";
private int typeNpcs;
private string npcPrefab;
private int lifeTimeNpcs;
private int npcsAmount;
private float npcDamageMultiplier;
private int npcHealth;
private const string npcName = "cpcguardnpc";
private bool randomEventTime;
private int minimumRemainToEvent;
private int maximumRemainToEvent;
private int minOnline;
private bool buildingBlock;
private int buildingBlockTime;
private int buildingBlockTimer;
private string npcKit;
private float npcAttackRange;
private ConfigData Configuration;
private List<Vector3> wayPoints = new List<Vector3>();
private List<BaseEntity> botList = new List<BaseEntity>();
private List<BaseEntity> entityList = new List<BaseEntity>();
private int coolDownTime = 7;
private int homeRadius = 20;
private int attackRadius = 75;
private MapMarkerGenericRadius marker;
private VendingMachineMapMarker vending;
private BaseEntity explosionMarker;
public static SphereEntity dome;
private class NpcBrain : FacepunchBehaviour {
public Vector3 homePosition;
public Vector3 targetPosition;
public BaseEntity target;
public int stateTimer;
public int moveChance;
}
private class MultipleZones {
public string name {
get;
set;
}
public int radius {
get;
set;
}
public Vector3 center {
get;
set;
}
}
private int zoneSequence = 0;
private class TimerForCrate : FacepunchBehaviour {
public Timer timer;
}
private class OwnerTimer : FacepunchBehaviour {
public Timer timer;
}
private float serverHackSeconds = HackableLockedCrate.requiredHackSeconds;
private List<Vector3> monumentsList = new List<Vector3>();
private int monumentsRadius;
public static BasePlayer eventOwner;
public static string enterMessage;
public static string ejectMessage;
public static string ownerLeaveMessage;
public static bool ejectPlayers;
public static int eventRadius;
public static int ownerLeftTime;
public static bool teamOwners;
public static bool adminDomeAllow;
public static List<Vector3> points = new List<Vector3>();
private string markerName;
private Timer eventTimer;
class ConfigData {
[JsonProperty("PVE mode (crates can only be looted by the player who first dealt damage to the NPC)")]
public bool pveMode = false;
[JsonProperty("Give event ownership to the owner's teammates if he is no longer the owner.Only if teammates are within the event radius (for PVE mode)")]
public bool teamOwners = true;
[JsonProperty("Radius for event(for PVE mode)")]
public int eventRadius = 380;
[JsonProperty("Create a dome for PVE mode")]
public bool createSphere = false;
[JsonProperty("Dome transparency (the higher the value, the darker the dome, recommended 4)")]
public int transparencySphere = 4;
[JsonProperty("Time after which the owner of the event will be deleted if he left the dome or left the server (for PVE mode)")]
public int ownerLeftTime = 300;
[JsonProperty("Message when a player enters the event dome(only for PVE mode if there is a dome)")]
public string enterMessage = "You have entered the Cargo Plane Crash Event";
[JsonProperty("Message when the event owner leaves the event dome (only for PVE mode if there is a dome)")]
public string ownerLeaveMessage = "Return to the event dome, otherwise after 300 seconds you will no longer be the owner of this event";
[JsonProperty("Do not allow other players into the event(only for PVE mode if there is a dome) Be careful, if the crash site is near the player's base and the player is not the owner of the event, he will be ejected from his base outside the dome")]
public bool ejectPlayers = false;
[JsonProperty("Message when a player is ejected from the event dome(only for PVE mode if there is a dome)")]
public string ejectMessage = "You cannot be here, you are not the owner of this event";
[JsonProperty("Allow admin to be in event dome (only for PVE mode if there is a dome)")]
public bool adminDomeAllow = true;
[JsonProperty("Triggering an event by timer (disable if you want to trigger the event only manually)")]
public bool timerStart = true;
[JsonProperty("Time to event start(in seconds)")]
public float remainToEvent = 3600f;
[JsonProperty("Random time to event start")]
public bool randomEventTime = false;
[JsonProperty("Minimum time to event start(in seconds)")]
public int minimumRemainToEvent = 600;
[JsonProperty("Maximum time to event start(in seconds)")]
public int maximumRemainToEvent = 10800;
[JsonProperty("CargoPlane speed(recommended 4 to 6)")]
public float speed = 5f;
[JsonProperty("Minimum amount of online players to trigger the event")]
public int minOnline = 1;
[JsonProperty("Crates amount(spawn after crash)")]
public int cratesAmount = 1;
[JsonProperty("Crate simple loot table name(plugin SimpleLootTable is required)")]
public string crateTableName = "";
[JsonProperty("Minimum number of items in a crate(plugin SimpleLootTable is required)")]
public int crateMinItems = 0;
[JsonProperty("Maximum number of items in a crate(plugin SimpleLootTable is required)")]
public int crateMaxItems = 0;
[JsonProperty("Crates lifetime(in seconds).The crate will not be destroyed if it has been activated")]
public int lifeTimeCrates = 3600;
[JsonProperty("Crates timer(in seconds)")]
public int timerCrates = 900;
[JsonProperty("Remove crates after being looted by a player(in seconds)")]
public int removeCratesTime = 300;
[JsonProperty("Airdrops amount(spawn after crash)")]
public int airdropsAmount = 1;
[JsonProperty("Airdrop simple loot table name(plugin SimpleLootTable is required)")]
public string airdropTableName = "";
[JsonProperty("Minimum number of items in an airdrop(plugin SimpleLootTable is required)")]
public int airdropMinItems = 0;
[JsonProperty("Maximum number of items in an airdrop(plugin SimpleLootTable is required)")]
public int airdropMaxItems = 0;
[JsonProperty("Airdrops lifetime(in seconds)")]
public int lifeTimeAirdrops = 3600;
[JsonProperty("Fireballs amount(spawn after crash)")]
public int fireballsAmount = 5;
[JsonProperty("Passengers amount(spawn after crash)")]
public int passengersAmount = 2;
[JsonProperty("Explosion marker on the map(spawn after crash)")]
public bool expMarker = true;
[JsonProperty("Explosion marker lifetime(in seconds)")]
public int lifeTimeExpMarker = 300;
[JsonProperty("Enable signal smoke(spawn after crash)")]
public bool signalSmoke = true;
[JsonProperty("Signal smoke lifetime(in seconds, max 214)")]
public int lifeTimeSignalSmoke = 214;
[JsonProperty("Map size(crash zone size), you can see the zone, use the chat command /showcrashzone")]
public float mapSize = 4500;
[JsonProperty("Starting altitude, defaults to map size, can be increased if cargo plane hits high ground(no more than 10000 recommended)")]
public float altitude = 4500;
[JsonProperty("Crash zone center.Use chat command /setcrashzonecenter to set to player position.You can check crash zone center, use the chat command /showcrashzone")]
public Vector3 crashZoneCenter = new Vector3(0, 0, 0);
[JsonProperty("Use multiple zones")]
public bool useMultipleZones = false;
[JsonProperty("Select a zone from the list sequentially(if false, then the crash zone will be chosen randomly)")]
public bool selectZoneSequentially = false;
[JsonProperty("Zones list")]
public List<MultipleZones> zonesList = new List<MultipleZones>() {
new MultipleZones {
name = "0", radius = 300, center = new Vector3(-300, 0, 0)
}
, new MultipleZones {
name = "1", radius = 200, center = new Vector3(100, 0, 0)
}
}
;
[JsonProperty("Event message(if empty, no message will be displayed)")]
public string message = "CargoPlane event started";
[JsonProperty("Crash message(if empty, no message will be displayed)")]
public string crashMessage = "Cargo plane crashed";
[JsonProperty("Event end message(if empty, no message will be displayed)")]
public string endMessage = "CargoPlaneCrash event ended";
[JsonProperty("Message about coordinates(will display the coordinates of the crash site.If empty, no message will be displayed)")]
public string coordMessage = "";
[JsonProperty("Kit name(you can use kits for passengers if you have Kits plugin)")]
public string kitName = "";
[JsonProperty("Passenger name")]
public string passengerName = "Mister bot";
[JsonProperty("Use NPC prefab for passengers")]
public bool passengerNPC = false;
[JsonProperty("NPCs amount(spawn after crash)")]
public int npcsAmount = 2;
[JsonProperty("NPCs lifetime(in seconds)")]
public int lifeTimeNpcs = 3600;
[JsonProperty("NPCs type(NPCs prefab, experimental setting, it is not known how the NPCs will behave) 0 - tunneldweller; 1 - underwaterdweller; 2 - excavator; 3 - full_any; 4 - lr300; 5 - mp5; 6 - pistol; 7 - shotgun; 8 - heavy; 9 - junkpile_pistol; 10 - oilrig; 11 - patrol; 12 - peacekeeper; 13 - roam; 14 - roamtethered; 15 - bandit_guard; 16 - cargo; 17 - cargo_turret_any; 18 - cargo_turret_lr300; 19 - ch47_gunner")]
public int typeNpcs = 8;
[JsonProperty("NPCs health(0 - default)")]
public int npcHealth = 0;
[JsonProperty("NPCs damage multiplier")]
public float npcDamageMultiplier = 1f;
[JsonProperty("NPCs accuracy(the lower the value, the more accurate, 0 - maximum accuracy)")]
public float npcAccuracy = 2f;
[JsonProperty("NPCs attack range")]
public float npcAttackRange = 75f;
[JsonProperty("Radius of chasing the player(NPCs will chase the player as soon as he comes closer than the specified radius, must be no greater than the attack range)")]
public float chaseRadius = 60;
[JsonProperty("Minimum distance to NPC damage")]
public float npcMinDistToDmg = 75f;
[JsonProperty("Message if the player attacks far away NPCs")]
public string npcFarAwayMessage = "NPC is too far away, he doesn't take damage";
[JsonProperty("Kit for NPCs.The NPC will use the weapon that is in the first slot of the belt(requires Kits plugin)")]
public string npcKit = "";
[JsonProperty("Default displayName for NPC(for SimpleKillFeed/DeathNotes plugin)")]
public string displayNameNPC = "Crashsite NPC";
[JsonProperty("List of displayNames for each NPC(for SimpleKillFeed/DeathNotes plugin)")]
public List<string> displayNamesListNPC = new List<string> {
"Crashsite NPC1", "Crashsite NPC2", "Crashsite NPC3"
}
;
[JsonProperty("Prohibit building near the crash site")]
public bool buildingBlock = false;
[JsonProperty("How long construction is prohibited near the crash site(in seconds)")]
public int buildingBlockTime = 1800;
[JsonProperty("Event marker on the map(spawn an event marker at the crash site)")]
public bool eventMarker = false;
[JsonProperty("Event marker name")]
public string markerName = "Cargo plane crash site";
[JsonProperty("Event marker lifetime(in seconds)")]
public int markerLifetime = 3600;
[JsonProperty("Event marker transparency(0-1)")]
public float markerAlpha = 0.75f;
[JsonProperty("Event marker radius")]
public float markerRadius = 0.5f;
[JsonProperty("Event marker color.R(0-1)")]
public float markerColorR = 1.0f;
[JsonProperty("Event marker color.G(0-1)")]
public float markerColorG = 0f;
[JsonProperty("Event marker color.B(0-1)")]
public float markerColorB = 0f;
[JsonProperty("Do not spawn crates and NPCs when a cargo plane falls under water (if the water depth is greater than)")]
public float spawnDepth = 0.5f;
[JsonProperty("Do not choose a crash site near monuments")]
public bool monumentsProhibition = false;
}
[HarmonyPatch(typeof(BasePlayer))]
[HarmonyPatch("displayName", MethodType.Getter)]
public static class DisplayNameScientistCPC1 {
static bool Prefix(ref string __result, BasePlayer __instance) {
if (__instance != null) {
BasePlayer bot = __instance.gameObject.GetComponent<BasePlayer>();
string npcname = "Scientist";
if (bot) {
if (bot._name != "#Passenger1818") return true;
npcname = passengerName;
}
__result = npcname;
return false;
}
return true;
}
}
[HarmonyPatch(typeof(ScientistNPC))]
[HarmonyPatch("displayName", MethodType.Getter)]
public static class DisplayNameScientistCPC {
static bool Prefix(ref string __result, ScientistNPC __instance) {
if (__instance != null) {
BasePlayer bot = __instance.gameObject.GetComponent<BasePlayer>();
string npcname = "Scientist";
if (bot) {
if (bot._lastSetName != "#Scientist1818") return true;
npcname = bot._name;
}
__result = npcname;
return false;
}
return true;
}
}
[HarmonyPatch(typeof(TunnelDweller))]
[HarmonyPatch("displayName", MethodType.Getter)]
public static class DisplayNameTunnelDwellerCPC {
static bool Prefix(ref string __result, ScientistNPC __instance) {
if (__instance != null) {
BasePlayer bot = __instance.gameObject.GetComponent<BasePlayer>();
string npcname = "Scientist";
if (bot) {
if (bot._lastSetName != "#Scientist1818") return true;
npcname = bot._name;
}
__result = npcname;
return false;
}
return true;
}
}
[HarmonyPatch(typeof(UnderwaterDweller))]
[HarmonyPatch("displayName", MethodType.Getter)]
public static class DisplayNameUnderwaterDwellerCPC {
static bool Prefix(ref string __result, ScientistNPC __instance) {
if (__instance != null) {
BasePlayer bot = __instance.gameObject.GetComponent<BasePlayer>();
string npcname = "Scientist";
if (bot) {
if (bot._lastSetName != "#Scientist1818") return true;
npcname = bot._name;
}
__result = npcname;
return false;
}
return true;
}
}
private Harmony harmony = new Harmony("CargoPlaneCrash");
private void OnServerInitialized() {
harmony.UnpatchAll("CargoPlaneCrash");
harmony.PatchAll(System.Reflection.Assembly.GetExecutingAssembly());
foreach (BasePlayer player in BasePlayer.activePlayerList) AddOwnerTimerForPlayer(player);
LoadConfig();
markerName = Configuration.markerName;
remainToEvent = Configuration.remainToEvent;
remain = remainToEvent;
speed = Configuration.speed;
cratesAmount = Configuration.cratesAmount;
airdropsAmount = Configuration.airdropsAmount;
fireballsAmount = Configuration.fireballsAmount;
passengersAmount = Configuration.passengersAmount;
expMarker = Configuration.expMarker;
mapSize = Configuration.mapSize / 4f;
altitude = Configuration.altitude;
message = Configuration.message;
kitName = Configuration.kitName;
passengerName = Configuration.passengerName;
crashZoneCenter = Configuration.crashZoneCenter;
lifeTimeExpMarker = Configuration.lifeTimeExpMarker;
lifeTimeCrates = Configuration.lifeTimeCrates;
lifeTimeAirdrops = Configuration.lifeTimeAirdrops;
signalSmoke = Configuration.signalSmoke;
lifeTimeSignalSmoke = Configuration.lifeTimeSignalSmoke;
typeNpcs = Configuration.typeNpcs;
npcHealth = Configuration.npcHealth;
npcDamageMultiplier = Configuration.npcDamageMultiplier;
npcsAmount = Configuration.npcsAmount;
lifeTimeNpcs = Configuration.lifeTimeNpcs;
randomEventTime = Configuration.randomEventTime;
minimumRemainToEvent = Configuration.minimumRemainToEvent;
maximumRemainToEvent = Configuration.maximumRemainToEvent;
minOnline = Configuration.minOnline;
buildingBlock = Configuration.buildingBlock;
buildingBlockTime = Configuration.buildingBlockTime;
npcKit = Configuration.npcKit;
npcAttackRange = Configuration.npcAttackRange;
if (lifeTimeSignalSmoke > 214) lifeTimeSignalSmoke = 214;
if (npcsAmount > 15) npcsAmount = 15;
ejectMessage = Configuration.ejectMessage;
enterMessage = Configuration.enterMessage;
ownerLeaveMessage = Configuration.ownerLeaveMessage;
ejectPlayers = Configuration.ejectPlayers;
eventRadius = Configuration.eventRadius;
ownerLeftTime = Configuration.ownerLeftTime;
teamOwners = Configuration.teamOwners;
adminDomeAllow = Configuration.adminDomeAllow;
Unsubscribe("OnTick");
Unsubscribe("OnEntitySpawned");
foreach (var item in TerrainMeta.Path.Monuments) monumentsList.Add(item.transform.position);
switch (typeNpcs) {
case 0 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/tunneldweller/npc_tunneldweller.prefab";
break;
case 1 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/underwaterdweller/npc_underwaterdweller.prefab";
break;
case 2 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_excavator.prefab";
break;
case 3 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_any.prefab";
break;
case 4 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_lr300.prefab";
break;
case 5 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_mp5.prefab";
break;
case 6 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_pistol.prefab";
break;
case 7 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_shotgun.prefab";
break;
case 8 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab";
break;
case 9 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_junkpile_pistol.prefab";
break;
case 10 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_oilrig.prefab";
break;
case 11 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_patrol.prefab";
break;
case 12 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_peacekeeper.prefab";
break;
case 13 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_roam.prefab";
break;
case 14 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_roamtethered.prefab";
break;
case 15 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/banditguard/npc_bandit_guard.prefab";
break;
case 16 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_cargo.prefab";
break;
case 17 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_cargo_turret_any.prefab";
break;
case 18 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_cargo_turret_lr300.prefab";
break;
case 19 : npcPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_ch47_gunner.prefab";
break;
}
if (randomEventTime) remainToEvent = UnityEngine.Random.Range(minimumRemainToEvent, maximumRemainToEvent);
remain = remainToEvent;
if (Configuration.timerStart) {
Puts("Event will start in " + remainToEvent.ToString() + " seconds");
timer.Every(1f, () => {
remain--;
buildingBlockTimer--;
if (remain < 0) {
int s = 0;
if (entity) s = -9999;
foreach (BasePlayer player in BasePlayer.activePlayerList) s++;
if (s >= minOnline) startEvent();
else {
remain = remainToEvent;
if (entity) Puts("The event is already running");
else Puts("Not enough online players on the server, event will not start!");
}
}
}
);
}
else Puts("The event will be triggered only in manual mode");
}
void SaveConfig(object config) => Config.WriteObject(config, true);
void LoadConfig() {
base.Config.Settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
Configuration = Config.ReadObject<ConfigData>();
SaveConfig(Configuration);
}
protected override void LoadDefaultConfig() {
var config = new ConfigData();
SaveConfig(config);
}
void startEvent() {
Interface.CallHook("CargoPlaneCrashStarted");
RemoveEvent();
Puts("Event started");
findTarget();
entity = GameManager.server.CreateEntity(prefabstr, new Vector3(0, 1000, 0), new Quaternion(), false);
entity.Spawn();
var str = "assets/bundled/prefabs/oilfireballsmall.prefab";
BaseEntity fire = GameManager.server.CreateEntity(str, entity.transform.position);
fire.Spawn();
fire.SetParent(entity);
fire.transform.localPosition = new Vector3(-6.8f, 6.8f, 3f);
Subscribe("OnTick");
if (message != null) foreach (BasePlayer player in BasePlayer.activePlayerList) player.ChatMessage(message);
entity.transform.position += Vector3.up * altitude;
if (randomEventTime) remainToEvent = UnityEngine.Random.Range(minimumRemainToEvent, maximumRemainToEvent);
remain = remainToEvent;
if (Configuration.timerStart) Puts("Next event will start in " + remainToEvent.ToString() + " seconds");
}
void OnTick() {
if (entity) {
entity.transform.LookAt(target);
direction = entity.transform.forward;
entity.transform.position += direction * speed;
if (Vector3.Distance(entity.transform.position, target) < speed) {
crashSite();
return;
}
if (Physics.Raycast(entity.transform.position + Vector3.up * 100, Vector3.down, out check, 200, layerS)) if (Vector3.Distance(check.point, entity.transform.position) < 3) crashSite();
}
}
void OnAirdrop(CargoPlane plane, Vector3 dropPosition) {
BaseEntity ent = plane as BaseEntity;
if (smokeFlag) {
ent.Kill();
smokeFlag = false;
}
}
void crashSite() {
timer.Once(1, () => {
eventTimer = timer.Every(10, () => {
if (vending) VendingUpdate(eventOwner);
for (int i = entityList.Count - 1; i > -1; i--) if (entityList[i] == null) {
entityList.Remove(entityList[i]);
}
if (entityList.Count == 0) {
foreach (BasePlayer player in BasePlayer.activePlayerList) player.ChatMessage(Configuration.endMessage);
RemoveEvent();
Puts("Event ended");
Interface.CallHook("CargoPlaneCrashEnded");
eventTimer.Destroy();
}
}
);
}
);
serverHackSeconds = HackableLockedCrate.requiredHackSeconds;
if (Configuration.crashMessage != null) foreach (BasePlayer player in BasePlayer.activePlayerList) player.ChatMessage(Configuration.crashMessage);
if (Configuration.coordMessage != "") foreach (BasePlayer player in BasePlayer.activePlayerList) player.ChatMessage(Configuration.coordMessage + PhoneController.PositionToGridCoord(entity.transform.position).ToString());
Interface.CallHook("CargoPlaneCrashCrashed");
entityList.Clear();
Vector3 pos = Vector3.zero;
crashPosition = entity.transform.position;
spawnItems.Add(Vector3.zero);
spawnItems.Clear();
spawnItem("assets/prefabs/npc/patrol helicopter/effects/heli_explosion.prefab", 1, true);
spawnItem("assets/prefabs/misc/supply drop/supply_drop.prefab", airdropsAmount, false);
spawnItem("assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab", cratesAmount, false);
spawnItem("assets/bundled/prefabs/oilfireballsmall.prefab", fireballsAmount, false);
SpawnPassenger(passengersAmount);
if (signalSmoke) spawnItem("assets/prefabs/tools/supply signal/grenade.supplysignal.deployed.prefab", 1, false);
if (expMarker) {
var str = "assets/prefabs/tools/map/explosionmarker.prefab";
var marker = GameManager.server.CreateEntity(str, entity.transform.position);
marker.Spawn();
explosionMarker = marker;
timer.Once(lifeTimeExpMarker, () => {
if (marker) marker.Kill();
}
);
}
if (Configuration.eventMarker) DrawMarker();
Unsubscribe("OnTick");
entity.Kill();
buildingBlockTimer = buildingBlockTime;
RaycastHit hit = new RaycastHit();
for (int i = 0; i < npcsAmount; i++) {
int s = 0;
for (int x = 0; x < 22; x++) {
s = 0;
pos = new Vector3(crashPosition.x + UnityEngine.Random.Range(-crashRadius, crashRadius), crashPosition.y, crashPosition.z + UnityEngine.Random.Range(-crashRadius, crashRadius));
hit = new RaycastHit();
if (Physics.Raycast(pos + Vector3.up * 100f, Vector3.down, out hit, 500f, layerS)) pos = hit.point;
for (int f = 0; f < spawnItems.Count; f++) {
if (Vector3.Distance(pos, spawnItems[f]) < 2) s++;
}
if (s == 0) {
spawnItems.Add(pos);
break;
}
}
if (WaterLevel.GetWaterDepth(hit.point, false, false) < Configuration.spawnDepth) {
if (s > 0) spawnItems.Add(pos);
var npc = GameManager.server.CreateEntity(npcPrefab, pos, new Quaternion(), true);
npc.Spawn();
entityList.Add(npc);
BasePlayer player = npc as BasePlayer;
player.name = npcName;
player._name = Configuration.displayNameNPC;
player._lastSetName = "#Scientist1818";
if (i < Configuration.displayNamesListNPC.Count) if (Configuration.displayNamesListNPC[i] != null) player._name = Configuration.displayNamesListNPC[i];
ScientistBrain brain = npc.GetComponent<ScientistBrain>();
BaseNavigator navigator = npc.GetComponent<BaseNavigator>();
NpcBrain brainNPC = npc.gameObject.AddComponent<NpcBrain>();
ScientistNPC scientistNPC = npc.gameObject.GetComponent<ScientistNPC>();
if (scientistNPC) {
scientistNPC.damageScale = npcDamageMultiplier;
scientistNPC.aimConeScale = Configuration.npcAccuracy;
}
TunnelDweller tunnelDweller = npc.gameObject.GetComponent<TunnelDweller>();
if (tunnelDweller) {
tunnelDweller.damageScale = npcDamageMultiplier;
tunnelDweller.aimConeScale = Configuration.npcAccuracy;
}
UnderwaterDweller underwaterDweller = npc.gameObject.GetComponent<UnderwaterDweller>();
if (underwaterDweller) {
underwaterDweller.damageScale = npcDamageMultiplier;
underwaterDweller.aimConeScale = Configuration.npcAccuracy;
}
navigator.CanUseNavMesh = false;
brain.AttackRangeMultiplier = 10f;
brain.VisionCone = -1;
brain.SenseRange = npcAttackRange;
brain.ListenRange = 15f;
brain.SenseTypes = EntityType.Player;
brain.MemoryDuration = 5f;
brain.TargetLostRange = npcAttackRange;
brain.CheckVisionCone = false;
brain.CheckLOS = true;
brain.IgnoreNonVisionSneakers = true;
brain.HostileTargetsOnly = false;
brain.IgnoreSafeZonePlayers = false;
brain.RefreshKnownLOS = true;
navigator.MaxRoamDistanceFromHome = navigator.BestMovementPointMaxDistance = navigator.BestRoamPointMaxDistance = 5f;
navigator.DefaultArea = "Walkable";
navigator.topologyPreference = ((TerrainTopology.Enum)TerrainTopology.EVERYTHING);
navigator.Agent.agentTypeID = -1372625422;
if (navigator.CanUseNavMesh) navigator.Init(player, navigator.Agent);
brainNPC.homePosition = pos;
brainNPC.stateTimer = 5;
brainNPC.moveChance = 22;
botList.Add(npc);
timer.Once(1f, () => {
if (npc) MoveToPosition(brain, navigator, npc.transform.position + Vector3.forward * 0.1f, 0);
}
);
timer.Every(3f, () => {
if (npc) NpcAI(npc);
}
);
if (npcKit != "") {
player.inventory.Strip();
Kits?.Call("GiveKit", player, npcKit);
}
if (npcHealth > 0) {
player.startHealth = npcHealth;
player.health = npcHealth;
}
timer.Once(lifeTimeNpcs, () => {
if (npc) npc.Kill();
}
);
}
else {
PrintWarning("NPC position is under water, so NPC will not spawn");
continue;
}
}
AddWayPoints(crashPosition, crashRadius);
}
public void SpawnPassenger(int amount) {
RaycastHit hit = new();
for (int i = 0; i < amount; i++) {
Vector3 pos = new Vector3(entity.transform.position.x + UnityEngine.Random.Range(-crashRadius, crashRadius), entity.transform.position.y, entity.transform.position.z + UnityEngine.Random.Range(-crashRadius, crashRadius));
if (Physics.Raycast(pos + Vector3.up * 150f, Vector3.down, out hit, 500f, layerS)) if (hit.point.y > pos.y) pos += Vector3.up * (hit.point.y - pos.y);
string prefab = botPrefab;
if (Configuration.passengerNPC) prefab = "assets/rust.ai/agents/npcplayer/npcplayertest.prefab";
var entityCrash = GameManager.server.CreateEntity(prefab, pos);
BasePlayer pl = entityCrash as BasePlayer;
if (!Configuration.passengerNPC) pl._name = "#Passenger1818";
entityCrash.Spawn();
entityList.Add(entityCrash);
pl.inventory.Strip();
if (kitName != "") Kits?.Call("GiveKit", pl, kitName);
if (Configuration.passengerNPC) {
pl._lastSetName = "#Scientist1818";
pl._name = passengerName;
pl.displayName = passengerName;
}
pl.Hurt(9999);
}
}
public void MoveToPosition(ScientistBrain brain, BaseNavigator navigator, Vector3 pos, int moveSpeed) {
var speed = BaseNavigator.NavigationSpeed.Slow;
if (moveSpeed == 1) speed = BaseNavigator.NavigationSpeed.Fast;
navigator.CanUseNavMesh = true;
brain.Navigator.SetDestination(pos, speed, 0f, 0f);
navigator.CanUseNavMesh = false;
}
public void NpcAI(BaseEntity npc) {
BaseNavigator navigator = npc.GetComponent<BaseNavigator>();
ScientistBrain brain = npc.GetComponent<ScientistBrain>();
NpcBrain x = npc.gameObject.GetComponent<NpcBrain>();
int speed = 0;
if (brain.Senses.Players.Count == 0) {
if (x.stateTimer == 0) {
brain.SwitchToState(AIState.Idle, 0);
x.moveChance = 22;
}
x.stateTimer--;
}
else {
x.stateTimer = coolDownTime;
speed = 1;
x.moveChance = 100;
if (brain.Senses.Players[0]) if (Vector3.Distance(brain.Senses.Players[0].transform.position, npc.transform.position) < Configuration.chaseRadius) {
BasePlayer player = brain.Senses.Players[0] as BasePlayer;
if (!player.IsAlive()) {
brain.Senses.Players.Remove(brain.Senses.Players[0]);
return;
}
float xx = UnityEngine.Random.Range(-2, 2);
float zz = UnityEngine.Random.Range(-2, 2);
Vector3 offset = new Vector3(xx, 0, zz);
x.targetPosition = brain.Senses.Players[0].transform.position + offset;
MoveToPosition(brain, navigator, x.targetPosition, 1);
return;
}
}
if (Vector3.Distance(npc.transform.position, x.homePosition) < homeRadius) {
if (!navigator.Moving) {
var chanсe = UnityEngine.Random.Range(0, 100);
if (chanсe < x.moveChance) {
var y = UnityEngine.Random.Range(0, wayPoints.Count);
Vector3 point = wayPoints[y] + Vector3.up * 0.5f;
RaycastHit check;
Vector3 vec = new Vector3(point.x - npc.transform.position.x, point.y - npc.transform.position.y, point.z - npc.transform.position.z);
if (!Physics.Raycast(npc.transform.position + Vector3.up * 0.5f, vec, out check, Vector3.Distance(npc.transform.position, point), layerS)) x.targetPosition = wayPoints[y];
else x.targetPosition = check.point - Vector3.Normalize(vec) * 0.5f;
MoveToPosition(brain, navigator, x.targetPosition, speed);
}
}
}
else if (x.stateTimer < 0) MoveToPosition(brain, navigator, x.homePosition, 1);
}
public void AddWayPoints(Vector3 center, float radius) {
wayPoints.Clear();
float off = 1;
for (float i = -radius / 2 + off; i < radius / 2 + off; i += 1) for (float ii = -radius / 2 + off; ii < radius / 2 + off; ii += 1) {
RaycastHit check;
Vector3 offset = new Vector3(i, 0, ii);
if (Physics.Raycast(center + offset + Vector3.up * 100, Vector3.down, out check, 200, layerS)) if (WaterLevel.GetWaterDepth(check.point, false, false) < Configuration.spawnDepth) {
BaseEntity entity = check.GetEntity();
if (!entity) wayPoints.Add(check.point);
}
}
}
void spawnItem(string str, int amount, bool effect) {
RaycastHit hit = new RaycastHit();
for (int i = 0; i < amount; i++) {
Vector3 pos = new Vector3(entity.transform.position.x + UnityEngine.Random.Range(-crashRadius, crashRadius), entity.transform.position.y, entity.transform.position.z + UnityEngine.Random.Range(-crashRadius, crashRadius));
hit = new RaycastHit();
if (Physics.Raycast(pos + Vector3.up * 50f, Vector3.down, out hit, 500f, layerS)) if (hit.point.y > pos.y) pos += Vector3.up * (hit.point.y - pos.y);
if (effect) Effect.server.Run(str, entity.transform.position);
else {
var entityCrash = GameManager.server.CreateEntity(str, pos);
entityCrash.Spawn();
entityList.Add(entityCrash);
if (str == "assets/prefabs/tools/supply signal/grenade.supplysignal.deployed.prefab") {
smokeFlag = true;
timer.Once(lifeTimeSignalSmoke, () => {
if (entityCrash) entityCrash.Kill();
}
);
}
if (str == "assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab") {
entityCrash.name = "cargoplanecrashcrate";
if (Configuration.crateTableName != "") SimpleLootTable?.Call("GetSetItems", entityCrash, Configuration.crateTableName, Configuration.crateMinItems, Configuration.crateMaxItems, 1f);
spawnItems.Add(entityCrash.transform.position);
HackableLockedCrate ent = entityCrash.GetComponent<HackableLockedCrate>();
ent.hackSeconds = serverHackSeconds - Configuration.timerCrates;
float oldTime = ent.hackSeconds;
TimerForCrate timerForCrate = ent.gameObject.AddComponent<TimerForCrate>();
timerForCrate.timer = timer.Every(1, () => {
if (Math.Abs(oldTime - ent.hackSeconds) > 5) if (ent.hackSeconds == 0 || ent.hackSeconds == 1) {
ent.hackSeconds = oldTime - 5;
if (ent.hackSeconds < serverHackSeconds - Configuration.timerCrates) ent.hackSeconds = serverHackSeconds - Configuration.timerCrates;
}
else {
if (ent.hackSeconds == 0 && Math.Abs(oldTime - ent.hackSeconds) == 0) ent.hackSeconds -= 5;
}
oldTime = ent.hackSeconds;
if (!ent) timerForCrate.timer.Destroy();
}
);
timer.Once(lifeTimeCrates, () => {
if (entityCrash) {
ent = entityCrash.GetComponent<HackableLockedCrate>();
if (ent.hackSeconds == serverHackSeconds - Configuration.timerCrates) ent.Kill();
}
}
);
}
if (entityCrash is SupplyDrop) {
entityCrash.name = "cargoplanecrashcrate";
if (Configuration.airdropTableName != "") SimpleLootTable?.Call("GetSetItems", entityCrash, Configuration.airdropTableName, Configuration.airdropMinItems, Configuration.airdropMaxItems, 1f);
spawnItems.Add(entityCrash.transform.position);
SupplyDrop supplyDrop = entityCrash as SupplyDrop;
var drop = supplyDrop.GetComponent<Rigidbody>();
supplyDrop.RemoveParachute();
drop.drag = 1f;
timer.Once(lifeTimeAirdrops, () => {
if (entityCrash) entityCrash.Kill();
}
);
}
}
}
}
object OnConstructionPlace(BaseEntity entity, Construction component, Construction.Target constructionTarget, BasePlayer player) {
if (buildingBlock) if (buildingBlockTimer > 0) if (entity is BuildingBlock) if (Vector3.Distance(player.transform.position, crashPosition) < crashRadius * 2) {
NextFrame(() => {
if (entity) entity.AdminKill();
}
);
player.ChatMessage("You can't build near the crash site");
}
return null;
}
private void OnEntityTakeDamage(BaseEntity entity, HitInfo info) {
var killer = info.Initiator as BasePlayer;
if (killer) {
if (entity.name == npcName) if (Vector3.Distance(entity.transform.position, killer.transform.position) > Configuration.npcMinDistToDmg) {
info.damageTypes.ScaleAll(0);
BasePlayer player = killer as BasePlayer;
if (player && player.IsConnected) player.ChatMessage(Configuration.npcFarAwayMessage);
}
else AddEventOwner(killer);
}
}
private object CanLootEntity(BasePlayer player, StorageContainer container) {
if (container) if (container.name != null) if (container.name == "cargoplanecrashcrate") {
bool flag = false;
if (eventOwner) {
if (eventOwner.Team != null) if (eventOwner.Team.members.Contains(player.userID)) flag = true;
if (player == eventOwner) flag = true;
if (!flag) {
player.ChatMessage("You can't loot this one");
return false;
}
}
timer.Once(Configuration.removeCratesTime, () => {
if (container) container.Kill();
}
);
}
return null;
}
void Unload() {
harmony.UnpatchAll("C
// ... [Code preview truncated due to length. Full source in attached file] ...