C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Rust;
using UnityEngine;
using System.Reflection;
namespace Oxide.Plugins {
[Info("Dangerous Treasures", "nivex", "1.2.9")]
[Description("Event with treasure chests.")]
public class DangerousTreasures : RustPlugin {
[PluginReference]
Plugin LustyMap, ZoneManager, Economics, ServerRewards, Map, GUIAnnouncements;
public static readonly FieldInfo AllScientists = typeof(Scientist).GetField("AllScientists", (BindingFlags.Static | BindingFlags.NonPublic));
static DangerousTreasures ins;
static bool unloading = false;
bool init = false;
bool wipeChestsSeed = false;
SpawnFilter filter = new SpawnFilter();
ItemDefinition boxDef;
static ItemDefinition rocketDef;
const string boxShortname = "box.wooden.large";
const string fireRocketShortname = "ammo.rocket.fire";
const string basicRocketShortname = "ammo.rocket.basic";
const string boxPrefab = "assets/prefabs/deployable/large wood storage/box.wooden.large.prefab";
const string spherePrefab = "assets/prefabs/visualization/sphere.prefab";
const string fireballPrefab = "assets/bundled/prefabs/oilfireballsmall.prefab";
static string rocketResourcePath;
DynamicConfigFile dataFile;
StoredData storedData = new StoredData();
Vector3 sd_customPos;
static int playerMask = LayerMask.GetMask("Player (Server)");
static int blockedMask = LayerMask.GetMask(new[] {
"Player (Server)", "Trigger", "Prevent Building"
}
);
static int obstructionMask = LayerMask.GetMask(new[] {
"Player (Server)", "Construction"
}
);
static int heightMask = LayerMask.GetMask(new[] {
"Terrain", "World", "Default", "Construction", "Deployed"
}
);
static int twdMask = LayerMask.GetMask(new[] {
"Terrain", "World", "Default"
}
);
static int twwMask = LayerMask.GetMask(new[] {
"Terrain", "World", "Water"
}
);
static int worldMask = LayerMask.GetMask("World", "Default");
List<int> BlockedLayers = new List<int> {
(int)Layer.Water, (int)Layer.Construction, (int)Layer.Trigger, (int)Layer.Prevent_Building, (int)Layer.Deployed, (int)Layer.Tree
}
;
static List<MonumentInfo> monuments = new List<MonumentInfo>();
// positions of monuments on the server
static List<uint> newmanProtections = new List<uint>();
List<ulong> indestructibleWarnings = new List<ulong>();
// indestructible messages limited to once every 10 seconds
List<ulong> drawGrants = new List<ulong>();
// limit draw to once every 15 seconds by default
Dictionary<Vector3, float> managedZones = new Dictionary<Vector3, float>();
static Dictionary<uint, MapInfo> mapMarkers = new Dictionary<uint, MapInfo>();
static Dictionary<uint, string> lustyMarkers = new Dictionary<uint, string>();
Dictionary<string, List<ulong>> skinsCache = new Dictionary<string, List<ulong>>();
Dictionary<string, List<ulong>> workshopskinsCache = new Dictionary<string, List<ulong>>();
static Dictionary<uint, TreasureChest> treasureChests = new Dictionary<uint, TreasureChest>();
static Dictionary<uint, string> looters = new Dictionary<uint, string>();
List<uint> storage = new List<uint>();
class MapInfo {
public string Url;
public string IconName;
public Vector3 Position;
public MapInfo() {
}
}
class TreasureItem {
public object shortname {
get;
set;
}
= string.Empty;
public object amount {
get;
set;
}
= 0;
public object skin {
get;
set;
}
= 0uL;
public TreasureItem() {
}
}
class PlayerInfo {
public int StolenChestsTotal {
get;
set;
}
= 0;
public int StolenChestsSeed {
get;
set;
}
= 0;
public PlayerInfo() {
}
}
class StoredData {
public double SecondsUntilEvent = double.MinValue;
public int TotalEvents = 0;
public readonly Dictionary<string, PlayerInfo> Players = new Dictionary<string, PlayerInfo>();
public List<uint> Markers = new List<uint>();
public string CustomPosition;
public StoredData() {
}
}
class GuidanceSystem : FacepunchBehaviour {
TimedExplosive missile;
ServerProjectile projectile;
BaseEntity target;
float rocketSpeedMulti = 2f;
Timer launch;
Vector3 launchPos;
List<ulong> exclude = new List<ulong>();
void Awake() {
missile = GetComponent<TimedExplosive>();
projectile = missile.GetComponent<ServerProjectile>();
launchPos = missile.transform.position;
launchPos.y = TerrainMeta.HeightMap.GetHeight(launchPos);
projectile.gravityModifier = 0f;
projectile.speed = 5f;
projectile.InitializeVelocity(Vector3.up);
missile.explosionRadius = 0f;
missile.timerAmountMin = timeUntilExplode;
missile.timerAmountMax = timeUntilExplode;
missile.damageTypes = new List<DamageTypeEntry>();
// no damage
missile.Spawn();
if (!missile) return;
launch = ins.timer.Once(targettingTime, () => {
if (!missile || missile.IsDestroyed) return;
var list = new List<BasePlayer>();
var entities = Pool.GetList<BaseEntity>();
Vis.Entities<BaseEntity>(launchPos, eventRadius + missileDetectionDistance, entities, playerMask, QueryTriggerInteraction.Collide);
foreach (var entity in entities) {
var player = entity as BasePlayer;
if (!player || player is NPCPlayer || !player.CanInteract()) continue;
if (ignoreFlying && player.IsFlying) continue;
if (exclude.Contains(player.userID) || newmanProtections.Contains(player.net.ID)) continue;
list.Add(player);
// acquire a player target
}
Pool.FreeList<BaseEntity>(ref entities);
if (list.Count > 0) {
SetTarget(list.GetRandom());
// pick a random player
list.Clear();
}
else if (!targetChest) {
missile.Kill();
return;
}
projectile.speed = rocketSpeed * rocketSpeedMulti;
InvokeRepeating(new Action(GuideMissile), 0.1f, 0.1f);
}
);
}
public void SetTarget(BaseEntity target) {
this.target = target;
}
public void Exclude(List<ulong> list) {
if (list != null && list.Count > 0) {
exclude.Clear();
exclude.AddRange(list);
}
}
void GuideMissile() {
if (target == null) return;
if (target.IsDestroyed) {
if (missile != null && !missile.IsDestroyed) {
missile.Kill();
}
return;
}
if (missile == null || missile.IsDestroyed || projectile == null) {
GameObject.Destroy(this);
return;
}
if (Vector3.Distance(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
}
void OnDestroy() {
exclude.Clear();
launch?.Destroy();
CancelInvoke(new Action(GuideMissile));
GameObject.Destroy(this);
}
}
class TreasureChest : FacepunchBehaviour {
public StorageContainer container;
public bool started = false;
long _unlockTime;
public Vector3 containerPos;
uint uid;
int countdownTime;
float posMulti = 3f;
float sphereMulti = 2f;
float claimTime;
float lastTick;
Vector3 lastFirePos;
bool firstEntered;
Dictionary<ulong, float> fireticks = new Dictionary<ulong, float>();
List<FireBall> fireballs = new List<FireBall>();
List<ulong> players = new List<ulong>();
List<ulong> newmans = new List<ulong>();
List<ulong> traitors = new List<ulong>();
List<uint> protects = new List<uint>();
List<TimedExplosive> missiles = new List<TimedExplosive>();
List<int> times = new List<int>();
List<SphereEntity> spheres = new List<SphereEntity>();
List<Vector3> missilePositions = new List<Vector3>();
List<Vector3> firePositions = new List<Vector3>();
Timer destruct, unlock, countdown, announcement;
public List<NPCPlayerApex> npcs = new List<NPCPlayerApex>();
List<Vector3> spawnpoints;
public bool HasNPC(ulong userID) {
return npcs.Any(x => x.userID == userID);
}
public Vector3 GetSpawn() {
if (monuments.Any(x => Vector3.Distance(x.transform.position, containerPos) < 50f)) {
return containerPos;
}
if (spawnpoints == null || spawnpoints.Count == 0) spawnpoints = BaseNetworkable.serverEntities.Where(e => e != null && e.transform != null && Vector3.Distance(e.transform.position, containerPos) < eventRadius * 0.75f && IsValidSpawn(e)).Select(e => new Vector3(e.transform.position.x, e.transform.position.y + 0.25f, e.transform.position.z)).ToList();
if (!undergroundLoot) {
spawnpoints.RemoveAll(e => e.y < containerPos.y);
}
var narrowed = spawnpoints.Where(x => Vector3.Distance(x, containerPos) < 15f).ToList();
if (narrowed.Count >= spawnNpcsAmount) {
return narrowed.GetRandom();
}
var spawnpoint = spawnpoints.Count > 2 ? spawnpoints.GetRandom() : containerPos;
return spawnpoint;
}
void Awake() {
container = GetComponent<StorageContainer>();
containerPos = container.transform.position;
uid = container.net.ID;
lastTick = Time.time;
gameObject.layer = (int)Layer.Reserved1;
var collider = gameObject.GetComponent<SphereCollider>() ?? gameObject.AddComponent<SphereCollider>();
collider.center = Vector3.zero;
collider.radius = eventRadius;
collider.isTrigger = true;
collider.enabled = true;
if (useSpheres && amountOfSpheres > 0) {
for (int i = 0; i < amountOfSpheres; i++) {
var sphere = GameManager.server.CreateEntity(spherePrefab, containerPos, new Quaternion(), true) as SphereEntity;
if (sphere != null) {
sphere.currentRadius = 1f;
sphere.Spawn();
sphere.LerpRadiusTo(eventRadius * sphereMulti, 5f);
spheres.Add(sphere);
}
else {
ins.Puts(ins.msg(szInvalidConstant, null, spherePrefab));
useSpheres = false;
break;
}
}
}
if (useRocketOpener) {
var positions = GetRandomPositions(containerPos, eventRadius * posMulti, numRockets, 0f);
foreach (var position in positions) CreateRocket(position, containerPos, Vector3.down);
positions.Clear();
}
if (useFireballs) {
firePositions = GetRandomPositions(containerPos, eventRadius, 25, containerPos.y + 25f);
if (firePositions.Count > 0) InvokeRepeating(new Action(SpawnFire), 0.1f, secondsBeforeTick);
}
if (launchMissiles) {
missilePositions = GetRandomPositions(containerPos, eventRadius, 25, 1);
if (missilePositions.Count > 0) {
InvokeRepeating(new Action(LaunchMissile), 0.1f, missileFrequency);
LaunchMissile();
}
}
}
void OnTriggerEnter(Collider col) {
if (started) return;
var player = col.GetComponentInParent<BasePlayer>();
if (!player || player is NPCPlayer || players.Contains(player.userID)) return;
if (showFirstEntered && !firstEntered) {
firstEntered = true;
string eventPos = FormatGridReference(containerPos);
foreach (var target in BasePlayer.activePlayerList) target.ChatMessage(ins.msg("OnFirstPlayerEntered", target.UserIDString, target.displayName, eventPos));
}
player.ChatMessage(ins.msg(useFireballs ? szProtected : szUnprotected, player.UserIDString));
players.Add(player.userID);
}
void OnTriggerExit(Collider col) {
if (!newmanProtect) return;
var player = col.GetComponentInParent<BasePlayer>();
if (!player || player is NPCPlayer) return;
if (protects.Contains(player.net.ID)) {
newmanProtections.Remove(player.net.ID);
protects.Remove(player.net.ID);
player.ChatMessage(ins.msg(szNewmanProtectFade, player.UserIDString));
}
}
void OnTriggerStay(Collider col) {
if (!useFireballs && !newmanMode && !newmanProtect) return;
if (started || Time.time - lastTick < 0.1f) return;
lastTick = Time.time;
var player = col.GetComponentInParent<BasePlayer>();
if (!player || player is NPCPlayer) return;
if (newmanMode || newmanProtect) {
int count = player.inventory.AllItems().Where(item => item.info.shortname != "torch" && item.info.shortname != "rock" && player.IsHostileItem(item))?.Count() ?? 0;
if (count == 0) {
if (newmanMode && !newmans.Contains(player.userID) && !traitors.Contains(player.userID)) {
player.ChatMessage(ins.msg(szNewmanEnter, player.UserIDString));
newmans.Add(player.userID);
}
if (newmanProtect && !newmanProtections.Contains(player.net.ID) && !protects.Contains(player.net.ID) && !traitors.Contains(player.userID)) {
player.ChatMessage(ins.msg(szNewmanProtect, player.UserIDString));
newmanProtections.Add(player.net.ID);
protects.Add(player.net.ID);
}
if (!traitors.Contains(player.userID)) return;
}
if (newmans.Contains(player.userID)) {
player.ChatMessage(ins.msg(useFireballs ? szNewmanTraitorBurn : szNewmanTraitor, player.UserIDString));
newmans.Remove(player.userID);
if (!traitors.Contains(player.userID)) traitors.Add(player.userID);
newmanProtections.Remove(player.net.ID);
protects.Remove(player.net.ID);
}
}
if (!useFireballs) return;
float stamp = Time.realtimeSinceStartup;
if (!fireticks.ContainsKey(player.userID)) fireticks[player.userID] = stamp + secondsBeforeTick;
if (fireticks[player.userID] - stamp <= 0) {
fireticks[player.userID] = stamp + secondsBeforeTick;
SpawnFire(player.transform.position);
}
}
void KillNpc() {
foreach (var npc in npcs.ToList()) {
if (npc != null && !npc.IsDestroyed) {
npc.Kill();
}
}
npcs.Clear();
}
void OnDestroy() {
ins.RemoveLustyMarker(uid);
ins.RemoveMapMarker(uid);
DestroyLauncher();
DestroySphere();
DestroyFire();
fireticks?.Clear();
players?.Clear();
times?.Clear();
unlock?.Destroy();
destruct?.Destroy();
countdown?.Destroy();
announcement?.Destroy();
KillNpc();
if (treasureChests.ContainsKey(uid)) {
treasureChests.Remove(uid);
if (!unloading && treasureChests.Count == 0) // 0.1.21 - nre fix
{
ins.SubscribeHooks(false);
}
}
GameObject.Destroy(this);
}
public void LaunchMissile() {
if (string.IsNullOrEmpty(rocketResourcePath)) launchMissiles = false;
if (!launchMissiles) {
DestroyLauncher();
return;
}
var missilePos = missilePositions.GetRandom();
float y = TerrainMeta.HeightMap.GetHeight(missilePos) + 15f;
missilePos.y = 200f;
RaycastHit hit;
if (Physics.Raycast(missilePos, Vector3.down, out hit, heightMask)) // don't want the missile to explode before it leaves its spawn location
missilePos.y = Mathf.Max(hit.point.y, y);
var missile = GameManager.server.CreateEntity(rocketResourcePath, missilePos, new Quaternion(), true) as TimedExplosive;
if (!missile) {
launchMissiles = false;
return;
}
missiles.Add(missile);
missiles.RemoveAll(x => x == null || x.IsDestroyed);
var gs = missile.gameObject.AddComponent<GuidanceSystem>();
gs.Exclude(newmans);
gs.SetTarget(container);
}
void SpawnFire() {
var firePos = firePositions.GetRandom();
int retries = firePositions.Count;
while (Vector3.Distance(firePos, lastFirePos) < eventRadius * 0.35f && --retries > 0) {
firePos = firePositions.GetRandom();
}
SpawnFire(firePos);
lastFirePos = firePos;
}
void SpawnFire(Vector3 firePos) {
if (!useFireballs) return;
if (fireballs.Count >= 6) // limit fireballs
{
foreach (var entry in fireballs) {
if (entry != null && !entry.IsDestroyed) entry.Kill();
fireballs.Remove(entry);
break;
}
}
var fireball = GameManager.server.CreateEntity(fireballPrefab, firePos, new Quaternion(), true) as FireBall;
if (fireball == null) {
ins.Puts(ins.msg(szInvalidConstant, null, fireballPrefab));
useFireballs = false;
CancelInvoke(new Action(SpawnFire));
firePositions.Clear();
return;
}
fireball.Spawn();
//fireball.enableSaving = false;
//BaseEntity.saveList.Remove(fireball);
fireball.damagePerSecond = fbDamagePerSecond;
fireball.generation = fbGeneration;
fireball.lifeTimeMax = fbLifeTimeMax;
fireball.lifeTimeMin = fbLifeTimeMin;
fireball.radius = fbRadius;
fireball.tickRate = fbTickRate;
fireball.waterToExtinguish = fbWaterToExtinguish;
fireball.SendNetworkUpdate();
fireball.Think();
float lifeTime = UnityEngine.Random.Range(fbLifeTimeMin, fbLifeTimeMax);
ins.timer.Once(lifeTime, () => fireball?.Extinguish());
fireballs.Add(fireball);
}
public void Destruct() {
unlock?.Destroy();
destruct?.Destroy();
if (container != null && !container.IsDestroyed) {
container.inventory.Clear();
container.Kill();
}
}
void Unclaimed() {
if (!started) return;
float time = claimTime - Time.realtimeSinceStartup;
if (time < 60f) return;
string eventPos = FormatGridReference(containerPos);
foreach (var target in BasePlayer.activePlayerList) target.ChatMessage(ins.msg(szDestroyingTreasure, target.UserIDString, eventPos, ins.FormatTime(time, target.UserIDString), szDistanceChatCommand));
}
public string GetUnlockTime(string userID = null) {
return started ? null : ins.FormatTime(_unlockTime - Time.realtimeSinceStartup, userID);
}
public void SetUnlockTime(float time) {
var posStr = FormatGridReference(containerPos);
countdownTime = Convert.ToInt32(time);
_unlockTime = Convert.ToInt64(Time.realtimeSinceStartup + time);
unlock = ins.timer.Once(time, () => {
if (container.HasFlag(BaseEntity.Flags.Locked)) container.SetFlag(BaseEntity.Flags.Locked, false);
if (container.HasFlag(BaseEntity.Flags.OnFire)) container.SetFlag(BaseEntity.Flags.OnFire, false);
if (showStarted) foreach (var target in BasePlayer.activePlayerList) SendDangerousMessage(target, containerPos, ins.msg(szEventStarted, target.UserIDString, posStr));
if (destructTime > 0f) destruct = ins.timer.Once(destructTime, () => Destruct());
DestroyFire();
DestroySphere();
DestroyLauncher();
started = true;
if (useUnclaimedAnnouncements) {
claimTime = Time.realtimeSinceStartup + destructTime;
announcement = ins.timer.Repeat(unclaimedInterval * 60f, 0, () => Unclaimed());
}
}
);
if (useCountdown && countdownTimes.Count > 0) {
if (times.Count == 0) times.AddRange(countdownTimes);
countdown = ins.timer.Repeat(1f, 0, () => {
countdownTime--;
if (started || times.Count == 0) {
countdown.Destroy();
return;
}
if (times.Contains(countdownTime)) {
string eventPos = FormatGridReference(containerPos);
foreach (var target in BasePlayer.activePlayerList) SendDangerousMessage(target, containerPos, ins.msg(szEventCountdown, target.UserIDString, eventPos, ins.FormatTime(countdownTime, target.UserIDString)));
times.Remove(countdownTime);
}
}
);
}
}
public void DestroyLauncher() {
if (missilePositions.Count > 0) {
CancelInvoke(new Action(LaunchMissile));
missilePositions.Clear();
}
if (missiles.Count > 0) {
foreach (var entry in missiles) if (entry != null && !entry.IsDestroyed) entry.Kill();
missiles.Clear();
}
}
public void DestroySphere() {
foreach (var sphere in spheres) if (sphere != null && !sphere.IsDestroyed) sphere.Kill();
}
public void DestroyFire() {
if (firePositions.Count > 0) {
CancelInvoke(new Action(SpawnFire));
firePositions.Clear();
}
if (useFireballs) {
foreach (var fireball in fireballs) {
if (fireball != null && !fireball.IsDestroyed) fireball.Kill();
}
fireballs.Clear();
}
newmanProtections.RemoveAll(x => protects.Contains(x));
traitors.Clear();
newmans.Clear();
protects.Clear();
}
}
void OnNewSave(string filename) => wipeChestsSeed = true;
void Init() {
SubscribeHooks(false);
}
void OnServerInitialized() {
if (init) return;
ins = this;
dataFile = Interface.Oxide.DataFileSystem.GetFile(Name);
try {
storedData = dataFile.ReadObject<StoredData>();
}
catch {
}
if (storedData?.Players == null) storedData = new StoredData();
LoadVariables();
if (chestLoot.Count == 0) {
Puts(msg(szUnloading, null, "Treasure"));
Interface.Oxide.UnloadPlugin(Name);
return;
}
if (automatedEvents) {
if (storedData.SecondsUntilEvent != double.MinValue) if (storedData.SecondsUntilEvent - Time.realtimeSinceStartup > eventIntervalMax) // Allows users to lower max event time
storedData.SecondsUntilEvent = double.MinValue;
eventTimer = timer.Repeat(1f, 0, () => CheckSecondsUntilEvent());
}
if (!string.IsNullOrEmpty(storedData.CustomPosition)) sd_customPos = storedData.CustomPosition.ToVector3();
else sd_customPos = Vector3.zero;
if (wipeChestsSeed) {
if (storedData.Players.Count > 0) {
var ladder = storedData.Players.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.StolenChestsSeed).ToList<KeyValuePair<string, int>>();
if (AssignTreasureHunters(ladder)) {
foreach (var kvp in storedData.Players.ToList()) {
storedData.Players[kvp.Key].StolenChestsSeed = 0;
}
}
}
sd_customPos = Vector3.zero;
storedData.CustomPosition = "";
wipeChestsSeed = false;
SaveData();
}
rocketDef = ItemManager.FindItemDefinition(useFireRockets ? fireRocketShortname : basicRocketShortname);
if (!rocketDef) {
ins.Puts(ins.msg(szInvalidConstant, null, useFireRockets ? fireRocketShortname : basicRocketShortname));
useRocketOpener = false;
}
else rocketResourcePath = rocketDef.GetComponent<ItemModProjectile>().projectileObject.resourcePath;
boxDef = ItemManager.FindItemDefinition(boxShortname);
if (!boxDef) {
Puts(msg(szInvalidConstant, null, boxShortname));
useRandomBoxSkin = false;
}
if (ZoneManager != null) {
var zoneIds = ZoneManager?.Call("GetZoneIDs");
if (zoneIds != null && zoneIds is string[]) {
foreach (var zoneId in (string[])zoneIds) {
var zoneLoc = ZoneManager?.Call("GetZoneLocation", zoneId);
if (zoneLoc is Vector3 && (Vector3)zoneLoc != Vector3.zero) {
var position = (Vector3)zoneLoc;
var zoneRadius = ZoneManager?.Call("GetZoneRadius", zoneId);
float distance = 0f;
if (zoneRadius is float && (float)zoneRadius > 0f) {
distance = (float)zoneRadius;
}
else {
var zoneSize = ZoneManager?.Call("GetZoneSize", zoneId);
if (zoneSize is Vector3 && (Vector3)zoneSize != Vector3.zero) {
var size = (Vector3)zoneSize;
distance = Mathf.Max(size.x, size.y);
}
}
if (distance > 0f) {
distance += eventRadius + 5f;
managedZones[position] = distance;
}
}
}
}
if (managedZones.Count > 0) Puts("Blocking events at zones: {0}", string.Join(", ", managedZones.Select(zone => string.Format("{0} ({1}: {2}m)", zone.Key.ToString().Replace("(", "").Replace(")", ""), FormatGridReference(zone.Key), zone.Value)).ToArray()));
}
if (!undergroundLoot) blacklistedMonuments.Add("Sewer");
monuments.AddRange(UnityEngine.Object.FindObjectsOfType<MonumentInfo>().Where(info => info?.transform != null && info.shouldDisplayOnMap).ToList());
if (monuments.Count == 0) {
onlyMonuments = false;
allowMonumentChance = 0f;
}
else {
foreach (var m in monuments.ToList()) {
if (blacklistedMonuments.Any(x => m.displayPhrase.english.ToLower().Trim() == x.ToLower().Trim())) {
monuments.Remove(m);
}
}
}
if (includeWorkshopBox || includeWorkshopTreasure) webrequest.Enqueue("http://s3.amazonaws.com/s3.playrust.com/icons/inventory/rust/schema.json", null, GetWorkshopIDs, this, Core.Libraries.RequestMethod.GET);
init = true;
RemoveAllTemporaryMarkers();
}
void Unload() {
if (!init) return;
unloading = true;
if (treasureChests.Count > 0) {
foreach (var entry in treasureChests) {
var container = BaseEntity.serverEntities.Find(entry.Key) as StorageContainer;
if (container == null) continue;
Puts(msg(szDestroyed, null, container.transform.position));
container.inventory?.Clear();
if (!container.IsDestroyed) container.Kill();
}
}
var objects = GameObject.FindObjectsOfType(typeof(TreasureChest));
// this isn't needed but doesn't hurt to be here
if (objects != null) foreach (var gameObj in objects) GameObject.Destroy(gameObj);
if (lustyMarkers.Count > 0) foreach (var entry in lustyMarkers.ToList()) RemoveLustyMarker(entry.Key);
if (mapMarkers.Count > 0) foreach (var entry in mapMarkers.ToList()) RemoveMapMarker(entry.Key);
BlockedLayers.Clear();
chestLoot?.Clear();
eventTimer?.Destroy();
indestructibleWarnings.Clear();
countdownTimes.Clear();
skinsCache.Clear();
workshopskinsCache.Clear();
RemoveAllTemporaryMarkers();
}
object CanBradleyApcTarget(BradleyAPC apc, BaseEntity entity) {
if (entity is NPCPlayer) {
var npc = entity as NPCPlayer;
if (treasureChests.Values.Any(x => x.HasNPC(npc.userID))) {
return false;
}
}
return null;
}
object OnNpcPlayerTarget(NPCPlayerApex npc, BaseEntity entity) {
if (init && entity?.transform != null && entity is BasePlayer) {
var player = entity as BasePlayer;
if (player.net != null && newmanProtections.Contains(player.net.ID)) {
return 0f;
}
else if (player is NPCPlayer && treasureChests.Values.Any(x => x.HasNPC(player.userID) && x.HasNPC(npc.userID))) {
return true;
}
}
return null;
}
void OnPlayerDie(BasePlayer player) {
if (!init || !player || !(player is NPCPlayer)) return;
var npc = player as NPCPlayer;
foreach (var chest in treasureChests.Values) {
if (chest.HasNPC(npc.userID)) {
player.svActiveItemID = 0;
player.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
break;
}
}
}
void OnEntitySpawned(BaseNetworkable entity) {
if (!init || entity == null) return;
if (entity as Scientist != null) {
AllScientists.SetValue((entity as Scientist), new HashSet<Scientist>());
// Steenamaroo fix for NPCPlayerApex.OnAiQuestion NullReferenceException #1
}
else if (entity is NPCPlayerCorpse) {
var corpse = entity as NPCPlayerCorpse;
if (treasureChests.Values.Any(x => x.HasNPC(corpse.playerSteamID))) {
if (spawnsDespawnInventory) {
NextTick(() => {
if (corpse != null && !corpse.IsDestroyed) {
corpse.containers[0].Clear();
corpse.containers[1].Clear();
corpse.containers[2].Clear();
}
}
);
}
var chest = treasureChests.Values.First(x => x.HasNPC(corpse.playerSteamID));
chest.npcs.RemoveAll(npc => npc.userID == corpse.playerSteamID);
if (treasureChests.Values.All(x => x.npcs.Count == 0)) {
Unsubscribe(nameof(OnNpcPlayerTarget));
Unsubscribe(nameof(CanBradleyApcTarget));
Unsubscribe(nameof(OnPlayerDie));
}
}
}
else if (entity is BaseLock) {
NextTick(() => {
if (entity != null && !entity.IsDestroyed) {
if (treasureChests.Values.Any(x => Vector3.Distance(entity.transform.position, x.containerPos) <= eventRadius)) {
entity.KillMessage();
}
}
}
);
}
}
object CanBuild(Planner plan, Construction prefab) {
if (!init || plan?.GetOwnerPlayer() == null) return null;
var player = plan.GetOwnerPlayer();
if (player.IsAdmin) return null;
foreach (var entry in treasureChests) {
if (Vector3.Distance(player.transform.position, entry.Value.containerPos) <= eventRadius) {
player.ChatMessage(msg(szBuildingBlocked, player.UserIDString));
return false;
}
}
return null;
}
object CanAcceptItem(ItemContainer container, Item item) {
if (!init || container?.entityOwner?.net == null) return null;
return treasureChests.ContainsKey(container.entityOwner.net.ID) ? (object)ItemContainer.CanAcceptResult.CannotAccept : null;
}
void OnLootEntity(BasePlayer player, BaseEntity entity) {
if (!init || player == null || entity?.net == null || !(entity is StorageContainer) || !treasureChests.ContainsKey(entity.net.ID)) return;
if (looters.ContainsKey(entity.net.ID)) looters.Remove(entity.net.ID);
looters.Add(entity.net.ID, player.UserIDString);
}
void OnItemRemovedFromContainer(ItemContainer container, Item item) {
if (container?.entityOwner == null || !(container.entityOwner is StorageContainer)) return;
NextTick(() => {
var box = container?.entityOwner as StorageContainer;
if (box?.net == null || !treasureChests.ContainsKey(box.net.ID)) return;
var looter = item.GetOwnerPlayer();
if (looter != null) {
if (looters.ContainsKey(box.net.ID)) looters.Remove(box.net.ID);
looters.Add(box.net.ID, looter.UserIDString);
}
if (box.inventory.itemList.Count == 0) {
if (looter == null && looters.ContainsKey(box.net.ID)) looter = BasePlayer.activePlayerList.Find(x => x.UserIDString == looters[box.net.ID]);
if (looter != null) {
if (recordStats) {
if (!storedData.Players.ContainsKey(looter.UserIDString)) storedData.Players.Add(looter.UserIDString, new PlayerInfo());
storedData.Players[looter.UserIDString].StolenChestsTotal++;
storedData.Players[looter.UserIDString].StolenChestsSeed++;
SaveData();
}
var posStr = FormatGridReference(looter.transform.position);
Puts(msg(szEventThief, null, posStr, looter.displayName));
foreach (var target in BasePlayer.activePlayerList) SendDangerousMessage(target, looter.transform.position, msg(szEventThief, target.UserIDString, posStr, looter.displayName));
looter.EndLooting();
if (useEconomics && economicsMoney > 0) {
if (Economics != null) {
Economics?.Call("Deposit", looter.UserIDString, economicsMoney);
looter.ChatMessage(msg(szEconomicsDeposit, looter.UserIDString, economicsMoney));
}
}
if (useServerRewards && serverRewardsPoints > 0) {
if (ServerRewards != null) {
var success = ServerRewards?.Call("AddPoints", looter.userID, serverRewardsPoints);
if (success != null && success is bool && (bool)success) looter.ChatMessage(msg(szRewardPoints, looter.UserIDString, serverRewardsPoints));
}
}
}
ins.RemoveLustyMarker(box.net.ID);
ins.RemoveMapMarker(box.net.ID);
if (!box.IsDestroyed) box.Kill();
if (treasureChests.Count == 0) SubscribeHooks(false);
}
}
);
}
object CanEntityTakeDamage(BaseEntity entity, HitInfo hitInfo) // TruePVE!!!! <3 @ignignokt84
{
if (entity == null || !(entity is BasePlayer) || hitInfo == null) {
return null;
}
if (truePVEServerWidePVP && hitInfo.InitiatorPlayer != null) // 1.2.9
{
return true;
}
return truePVEAllowPVPAtEvents && EventTerritory(hitInfo.PointStart) && EventTerritory(hitInfo.PointEnd) ? (object)true : null;
}
bool EventTerritory(Vector3 position) {
return treasureChests.Values.Any(x => Vector3.Distance(x.containerPos, new Vector3(position.x, x.containerPos.y, position.z)) <= eventRadius);
}
void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) {
if (!init || entity?.net == null) return;
bool newman = newmanProtections.Contains(entity.net.ID);
bool chest = treasureChests.ContainsKey(entity.net.ID);
if (newman || chest) {
var attacker = hitInfo?.InitiatorPlayer ?? null;
if (attacker) {
var uid = attacker.userID;
if (!indestructibleWarnings.Contains(uid)) {
indestructibleWarnings.Add(uid);
timer.Once(10f, () => indestructibleWarnings.Remove(uid));
attacker.ChatMessage(msg(chest ? szIndestructible : szNewmanProtected, attacker.UserIDString));
}
}
if (hitInfo != null && hitInfo.hasDamage) {
hitInfo.damageTypes.ScaleAll(0f);
}
}
var npc = entity as NPCPlayer;
if (npc == null || !treasureChests.Values.Any(x => x.HasNPC(npc.userID))) return;
if (hitInfo.hasDamage && hitInfo.damageTypes.GetMajorityDamageType() == DamageType.Heat) // make npc's immune to fire
{
hitInfo.damageTypes = new DamageTypeList();
return;
}
}
void SaveData() => dataFile.WriteObject(storedData);
void SubscribeHooks(bool flag) {
if (flag && init) {
if (spawnNpcs) {
Subscribe(nameof(OnEntitySpawned));
Subscribe(nameof(OnPlayerDie));
}
if (truePVEAllowPVPAtEvents || truePVEServerWidePVP) {
Subscribe(nameof(CanEntityTakeDamage));
}
Subscribe(nameof(CanBradleyApcTarget));
Subscribe(nameof(OnNpcPlayerTarget));
Subscribe(nameof(OnEntityTakeDamage));
Subscribe(nameof(OnItemRemovedFromContainer));
Subscribe(nameof(OnLootEntity));
Subscribe(nameof(CanAcceptItem));
Subscribe(nameof(CanBuild));
}
else {
Unsubscribe(nameof(CanEntityTakeDamage));
Unsubscribe(nameof(CanBradleyApcTarget));
Unsubscribe(nameof(OnNpcPlayerTarget));
Unsubscribe(nameof(OnEntitySpawned));
Unsubscribe(nameof(OnEntityTakeDamage));
Unsubscribe(nameof(OnItemRemovedFromContainer));
Unsubscribe(nameof(OnLootEntity));
Unsubscribe(nameof(CanAcceptItem));
Unsubscribe(nameof(CanBuild));
Unsubscribe(nameof(OnPlayerDie));
}
}
static void CreateRocket(Vector3 rocketPos, Vector3 targetPos, Vector3 offset) {
if (!useRocketOpener || rocketDef == null) return;
var rocket = GameManager.server.CreateEntity(rocketResourcePath, rocketPos, new Quaternion(), true) as TimedExplosive;
if (!rocket) {
ins.Puts(ins.msg(szInvalidConstant, null, "Rocket Creation"));
useRocketOpener = false;
return;
}
var projectile = rocket.GetComponent<ServerProjectile>();
var direction = (targetPos - rocketPos) + offset;
projectile.gravityModifier = 0f;
projectile.speed = rocketSpeed;
projectile.InitializeVelocity(direction);
rocket.timerAmountMin = 10f;
rocket.timerAmountMax = 20f;
//rocket.damageTypes = new List<DamageTypeEntry>(); // no damage
foreach (var type in rocket.damageTypes) {
type.amount = rocketDamageAmount;
}
rocket.Spawn();
}
static List<Vector3> GetRandomPositions(Vector3 destination, float radius, int amount, float y) {
var positions = new List<Vector3>();
if (amount <= 0) return positions;
int retries = 100;
float space = (radius / amount);
// space each rocket out from one another
for (int i = 0; i < amount; i++) {
var position = destination + UnityEngine.Random.insideUnitSphere * radius;
position.y = y != 0f ? y : UnityEngine.Random.Range(100f, 200f);
var match = positions.FirstOrDefault(p => Vector3.Distance(p, position) < space);
if (match != Vector3.zero) {
if (--retries < 0) break;
i--;
continue;
}
retries = 100;
positions.Add(position);
}
return positions;
}
public Vector3 GetEventPosition() {
if (sd_customPos != Vector3.zero) return sd_customPos;
var eventPos = Vector3.zero;
int maxRetries = 100;
if (allowMonumentChance > 0f && UnityEngine.Random.Range(0.1f, 1.0f) >= allowMonumentChance) {
return GetMonumentDropPosition();
}
if (onlyMonuments) {
return GetMonumentDropPosition();
}
do {
eventPos = GetSafeDropPosition(RandomDropPosition());
if (eventPos == Vector3.zero) continue;
if (Interface.CallHook("OnDangerousOpen", eventPos) != null) {
eventPos = Vector3.zero;
continue;
}
if (treasureChests.Values.Any(x => Vector3.Distance(x.containerPos, eventPos) < eventRadius)) {
eventPos = Vector3.zero;
continue;
}
// ... [Code preview truncated due to length. Full source in attached file] ...