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;
namespace Oxide.Plugins {
[Info("Dangerous Treasures", "nivex", "1.1.4", ResourceId = 2479)]
[Description("Event with treasure chests.")]
public class DangerousTreasures : RustPlugin {
[PluginReference]
Plugin LustyMap, ZoneManager, Economics, ServerRewards, Map, GUIAnnouncements;
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 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");
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
}
;
List<Vector3> monuments = new List<Vector3>();
// positions of monuments on the server
static List<uint> newmanProtections = new List<uint>();
static List<FireBall> spawnedFireballs = new List<FireBall>();
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> treasureLooters = new Dictionary<uint, string>();
static Dictionary<uint, List<NPCPlayer>> npcs = new Dictionary<uint, List<NPCPlayer>>();
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 : MonoBehaviour {
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<BaseEntity>();
var colliders = Pool.GetList<Collider>();
Vis.Colliders(launchPos, eventRadius + missileDetectionDistance, colliders, playerMask, QueryTriggerInteraction.Collide);
foreach (var collider in colliders) {
var player = collider.GetComponentInParent<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<Collider>(ref colliders);
if (list.Count > 0) {
SetTarget(list.GetRandom());
// pick a random player
list.Clear();
}
else if (!targetChest) {
missile.Kill();
return;
}
projectile.speed = rocketSpeed * rocketSpeedMulti;
InvokeHandler.InvokeRepeating(this, 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 || !missile || missile.IsDestroyed) return;
if (target.IsDestroyed) {
if (missile != null && !missile.IsDestroyed) missile.Kill();
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();
InvokeHandler.CancelInvoke(this, GuideMissile);
GameObject.Destroy(this);
}
}
class TreasureChest : MonoBehaviour {
public StorageContainer container;
public bool started = false;
long _unlockTime;
bool lerped = false;
public Vector3 containerPos;
uint uid;
int countdownTime;
float posMulti = 3f;
float sphereMulti = 2f;
float claimTime;
float lastStayTick;
Vector3 lastFirePos;
Dictionary<ulong, long> fireticks = new Dictionary<ulong, long>();
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;
void Awake() {
container = GetComponent<StorageContainer>();
containerPos = container.transform.position;
uid = container.net.ID;
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;
lastStayTick = Time.time;
if (useSpheres && amountOfSpheres > 0) {
for (int i = 0; i < amountOfSpheres; i++) {
if (!useSpheres) break;
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;
lerped = true;
// bug fix for prefab being invalid, otherwise event will not continue
}
}
if (useSpheres) InvokeHandler.InvokeRepeating(this, LerpUpdate, 0.1f, 0.1f);
}
else lerped = true;
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) InvokeHandler.InvokeRepeating(this, SpawnFire, 0.1f, secondsBeforeTick);
}
if (launchMissiles) {
missilePositions = GetRandomPositions(containerPos, eventRadius, 25, 1);
if (missilePositions.Count > 0) {
InvokeHandler.InvokeRepeating(this, LaunchMissile, 0.1f, missileFrequency);
LaunchMissile();
}
}
}
void LerpUpdate() {
foreach (var sphere in spheres) {
if (sphere != null && sphere.currentRadius == sphere.lerpRadius) {
InvokeHandler.CancelInvoke(this, LerpUpdate);
lerped = true;
break;
}
}
}
void OnTriggerEnter(Collider col) {
if (started) return;
var player = col.GetComponentInParent<BasePlayer>();
if (!player || player is NPCPlayer || players.Contains(player.userID)) return;
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) return;
if (protects.Contains(player.net.ID)) {
if (newmanProtections.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 || !lerped || Time.time - lastStayTick < 0.1f) return;
lastStayTick = 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);
if (newmanProtections.Contains(player.net.ID)) newmanProtections.Remove(player.net.ID);
if (protects.Contains(player.net.ID)) protects.Remove(player.net.ID);
}
}
if (!useFireballs) return;
var stamp = TimeStamp();
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 entry in npcs.ToList()) {
if (entry.Key == uid) {
foreach (var npc in entry.Value.ToList()) {
if (npc != null && !npc.IsDestroyed) {
npc.Kill();
}
}
npcs.Remove(entry.Key);
}
}
}
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;
}
if (!lerped) 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);
foreach (var entry in missiles.ToList()) if (entry == null || entry.IsDestroyed) missiles.Remove(entry);
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 || !lerped) return;
if (fireballs.Count >= 6) // limit fireballs
{
foreach (var entry in fireballs) {
if (entry != null && !entry.IsDestroyed) entry.Kill();
fireballs.Remove(entry);
if (spawnedFireballs.Contains(entry)) spawnedFireballs.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;
if (firePositions.Count > 0) {
InvokeHandler.CancelInvoke(this, SpawnFire);
firePositions.Clear();
}
return;
}
fireball.Spawn();
fireballs.Add(fireball);
}
public void Destruct() {
unlock?.Destroy();
destruct?.Destroy();
if (container != null) {
container.inventory?.Clear();
if (!container.IsDestroyed) container.Kill();
}
}
void Unclaimed() {
if (!started) return;
float time = claimTime - TimeStamp();
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 long UnlockTime {
get {
return this._unlockTime;
}
}
public void SetUnlockTime(float time) {
var posStr = FormatGridReference(containerPos);
countdownTime = Convert.ToInt32(time);
_unlockTime = Convert.ToInt64(TimeStamp() + 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 = TimeStamp() + 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) {
InvokeHandler.CancelInvoke(this, 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) {
InvokeHandler.CancelInvoke(this, SpawnFire);
firePositions.Clear();
}
if (useFireballs) {
foreach (var fireball in fireballs) {
if (fireball != null && !fireball.IsDestroyed) fireball.Kill();
if (spawnedFireballs.Contains(fireball)) spawnedFireballs.Remove(fireball);
}
fireballs.Clear();
}
foreach (var protect in protects) if (newmanProtections.Contains(protect)) newmanProtections.Remove(protect);
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(Title.Replace(" ", ""));
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 - TimeStamp() > 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();
}
if (useRocketOpener) {
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: ", string.Join(", ", managedZones.Select(zone => string.Format("{0} ({1}m)", FormatGridReference(zone.Key), zone.Value)).ToArray()));
}
monuments = UnityEngine.Object.FindObjectsOfType<MonumentInfo>().Select(monument => monument.transform.position).ToList();
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 (spawnedFireballs.Count > 0) {
foreach (var entry in spawnedFireballs) if (entry != null && !entry.IsDestroyed) entry.Kill();
spawnedFireballs.Clear();
}
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();
}
private object OnNpcPlayerTarget(NPCPlayerApex npc, BaseEntity entity) {
if (entity is BasePlayer) {
var player = entity as BasePlayer;
if (player.net != null && newmanProtections.Contains(player.net.ID)) {
return 0f;
}
}
return null;
}
void OnPlayerDie(BasePlayer player) {
var npc = player as NPCPlayer;
if (npc == null || !npcs.Any(entry => entry.Value.Contains(npc))) return;
player.svActiveItemID = 0;
player.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
void OnEntitySpawned(BaseNetworkable entity) {
if (!init || entity == null || (!(entity is FireBall)) && !(entity is BaseLock) && !(entity is NPCPlayerCorpse)) return;
if (entity is NPCPlayerCorpse) {
if (spawnsDespawnInventory) {
var corpse = entity as NPCPlayerCorpse;
foreach (var entry in npcs) {
foreach (var npc in entry.Value) {
if (npc.userID == corpse.playerSteamID) {
NextTick(() => {
corpse.containers[0].Clear();
corpse.containers[1].Clear();
corpse.containers[2].Clear();
}
);
break;
}
}
}
}
return;
}
NextTick(() => {
if (entity == null || entity.transform == null) return;
foreach (var entry in treasureChests) {
if (Vector3.Distance(entity.transform.position, entry.Value.containerPos) <= eventRadius + 25f) // some extra distance for fireballs that travel outside the sphere, usually on hills
{
if (entity is FireBall) {
var fireball = entity as FireBall;
ModifyFireball(fireball);
}
else if (entity is BaseLock || entity is CodeLock) {
entity.KillMessage();
}
break;
}
}
}
);
}
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 (treasureLooters.ContainsKey(entity.net.ID)) treasureLooters.Remove(entity.net.ID);
treasureLooters.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 (treasureLooters.ContainsKey(box.net.ID)) treasureLooters.Remove(box.net.ID);
treasureLooters.Add(box.net.ID, looter.UserIDString);
}
if (box.inventory.itemList.Count == 0) {
if (looter == null && treasureLooters.ContainsKey(box.net.ID)) looter = BasePlayer.activePlayerList.Find(x => x.UserIDString == treasureLooters[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);
}
}
);
}
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));
}
}
hitInfo?.damageTypes?.ScaleAll(0f);
}
}
void SaveData() {
if (storedData != null) {
dataFile.WriteObject(storedData);
}
}
void SubscribeHooks(bool flag) {
if (flag) {
if (init) {
if (useFireballs || spawnNpcs) {
Subscribe(nameof(OnEntitySpawned));
Subscribe(nameof(OnPlayerDie));
}
Subscribe(nameof(OnEntityTakeDamage));
Subscribe(nameof(OnItemRemovedFromContainer));
Subscribe(nameof(OnLootEntity));
Subscribe(nameof(CanAcceptItem));
Subscribe(nameof(CanBuild));
}
}
else {
Unsubscribe(nameof(OnEntitySpawned));
Unsubscribe(nameof(OnEntityTakeDamage));
Unsubscribe(nameof(OnItemRemovedFromContainer));
Unsubscribe(nameof(OnLootEntity));
Unsubscribe(nameof(CanAcceptItem));
Unsubscribe(nameof(CanBuild));
Unsubscribe(nameof(OnPlayerDie));
}
}
static void ModifyFireball(FireBall fireball) {
fireball.enableSaving = false;
if (BaseEntity.saveList.Contains(fireball)) 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();
spawnedFireballs.Add(fireball);
float lifeTime = UnityEngine.Random.Range(fbLifeTimeMin, fbLifeTimeMax);
ins.timer.Once(lifeTime, () => fireball?.Extinguish());
}
static void CreateRocket(Vector3 rocketPos, Vector3 targetPos, Vector3 offset) {
if (!useRocketOpener || rocketDef == null) return;
var rocket = GameManager.server.CreateEntity(rocketDef.GetComponent<ItemModProjectile>().projectileObject.resourcePath, 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;
do {
eventPos = GetSafeDropPosition(RandomDropPosition());
if (Interface.CallHook("OnDangerousOpen", eventPos) != null) {
eventPos = Vector3.zero;
continue;
}
if (managedZones.Count > 0) {
foreach (var zone in managedZones) {
if (Vector3.Distance(zone.Key, eventPos) <= zone.Value) {
eventPos = Vector3.zero;
// blocked by zone manager
break;
}
}
}
foreach (var monument in monuments) {
if (Vector3.Distance(eventPos, monument) < 150f) // don't put the treasure chest near a monument
{
eventPos = Vector3.zero;
break;
}
}
}
while (eventPos == Vector3.zero && --maxRetries > 0);
return eventPos;
}
public Vector3 GetSafeDropPosition(Vector3 position) {
RaycastHit hit;
position.y += 200f;
if (Physics.Raycast(position, Vector3.down, out hit)) {
if (hit.collider?.gameObject == null) return Vector3.zero;
if (!BlockedLayers.Contains(hit.collider.gameObject.layer)) {
position.y = Mathf.Max(hit.point.y, TerrainMeta.HeightMap.GetHeight(position));
var colliders = Pool.GetList<Collider>();
Vis.Colliders(position, eventRadius, colliders, blockedMask, QueryTriggerInteraction.Collide);
bool blocked = colliders.Count > 0;
Pool.FreeList<Collider>(ref colliders);
if (!blocked) return position;
}
}
return Vector3.zero;
}
public Vector3 RandomDropPosition() // CargoPlane.RandomDropPosition()
{
var vector = Vector3.zero;
float num = 100f, x = TerrainMeta.Size.x / 3f;
do {
vector = Vector3Ex.Range(-x, x);
}
while (filter.GetFactor(vector) == 0f && (num -= 1f) > 0f);
vector.y = 0f;
return vector;
}
static long TimeStamp() => (DateTime.Now.Ticks - DateTime.Parse("01/01/1970 00:00:00").Ticks) / 10000000;
void GetWorkshopIDs(int code, string response) {
if (response != null && code == 200) {
var items = JsonConvert.DeserializeObject<Rust.Workshop.ItemSchema>(response).items;
foreach (var item in items) {
if (string.IsNullOrEmpty(item.itemshortname) || string.IsNullOrEmpty(item.workshopdownload)) continue;
if (!workshopskinsCache.ContainsKey(item.itemshortname)) workshopskinsCache.Add(item.itemshortname, new List<ulong>());
workshopskinsCache[item.itemshortname].Add(Convert.ToUInt64(item.workshopdownload));
}
}
}
List<ulong> GetItemSkins(ItemDefinition def) {
if (!skinsCache.ContainsKey(def.shortname)) {
var skins = new List<ulong>();
skins.AddRange(def.skins.Select(skin => Convert.ToUInt64(skin.id)));
if ((def.shortname == boxShortname && includeWorkshopBox) || (def.shortname != boxShortname && includeWorkshopTreasure)) {
if (workshopskinsCache.ContainsKey(def.shortname)) {
skins.AddRange(workshopskinsCache[def.shortname]);
workshopskinsCache.Remove(def.shortname);
}
}
if (skins.Cont
// ... [Code preview truncated due to length. Full source in attached file] ...