C#:
// Plugin formatted by redBDGR's Plugin Formatting Tool
using Oxide.Core;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using Oxide.Core.Configuration;
namespace Oxide.Plugins
{
[Info("RustTanic", "redBDGR", "1.0.3f")]
[Description("Server event for the Cargo Ship Модернизация от Ernieleo")]
class RustTanic : RustPlugin
{
private bool Changed = false;
private static RustTanic plugin;
private TitanicManager manager;
private int worldLayer = LayerMask.GetMask("World");
private int defaultLayer = LayerMask.GetMask("Default");
private FieldInfo tooHotUntil = typeof(HelicopterDebris).GetField("tooHotUntil", (BindingFlags.Instance | BindingFlags.NonPublic));
private const string permissionNameADMIN = "rusttanic.admin";
private List<ItemInfo> floatingCrateTable = new List<ItemInfo>();
private List<ItemInfo> icebergCrateTable = new List<ItemInfo>();
private class ConfigFile
{
public static float sequencingGaps = 60f;
public static float spawnDistance = 3f;
public static float boatSpeed = 1f;
public static bool disableIcebergsWithCupboard = true;
public static bool disableIcebergsWithBuilding = true;
public static bool debugMode = false;
public static int floatingCratesToSpawn = 7;
public static float floatingCratesRadius = 30f;
public static float floatingCrateDespawnTime = 900f;
public static int floatingCrateMinItems = 3;
public static int floatingCrateMaxItems = 6;
public static int debisToSpawn = 4;
public static int lootPerDebris = 1;
public static float hackableCrateSeconds = 60f;
public static bool spawnIcebergCrates = true;
public static int icebergCratesToSpawn = 3;
public static float icebergCratesSpawnRadius = 6f;
public static string icebergCratePrefab = "assets/bundled/prefabs/radtown/crate_elite.prefab";
public static int icebergCrateMinItems = 3;
public static int icebergCrateMaxItems = 5;
public static bool killBoatScientists = true;
public static int icebergNPCToSpawn = 5;
public static float icebergNPCSpawnRadius = 10f;
public static string icebergNPCType = "assets/prefabs/npc/scientist/scientist.prefab";
public static string icebergNPCNames = "Pirate";
public static bool boatExhaustFlames = true;
public static bool boatRotatingLights = true;
public static bool disableExtraEffects = false;
public static float boatHornInterval = 20f;
public static bool randomEventEnabled = true;
public static float minRandomEventTime = 7200f;
public static float maxRandomEventTime = 10800;
public static int minPlayersForEvent = 1;
public static bool targetIcebergMarkerEnabled = true;
public static float targetIcebergMarkerRadius = 20f;
public static string targetIcerbergText = "Предположительное место крушения";
}
private void LoadVariables()
{
ConfigFile.sequencingGaps = Convert.ToSingle(GetConfig("Settings", "Задержка между этапами погружения", 60f));
ConfigFile.spawnDistance = Convert.ToSingle(GetConfig("Settings", "Расстояние спавна", 2f));
ConfigFile.boatSpeed = Convert.ToSingle(GetConfig("Settings", "Скорость хода", 1f));
ConfigFile.debugMode = Convert.ToBoolean(GetConfig("Settings", "DebugMode", false));
ConfigFile.disableIcebergsWithCupboard = Convert.ToBoolean(GetConfig("Settings", "Отключить Айсберги с билдинг шкафами", true));
ConfigFile.disableIcebergsWithBuilding = Convert.ToBoolean(GetConfig("Settings", "Отключить Айсберги с строениями", true));
ConfigFile.hackableCrateSeconds = Convert.ToSingle(GetConfig("General Loot", "Таймер взлома ящика", 60f));
ConfigFile.spawnIcebergCrates = Convert.ToBoolean(GetConfig("Iceberg Loot", "Спавн ящиков на Айсберге", true));
ConfigFile.icebergCratesToSpawn = Convert.ToInt16(GetConfig("Iceberg Loot", "Кол-во ящиков на Айсберге", 3));
ConfigFile.icebergCratesSpawnRadius = Convert.ToSingle(GetConfig("Iceberg Loot", "Радиус спавна ящиков", 6f));
ConfigFile.icebergCratePrefab = Convert.ToString(GetConfig("Iceberg Loot", "Prefab ящика", "assets/bundled/prefabs/radtown/crate_elite.prefab"));
ConfigFile.icebergCrateMinItems = Convert.ToInt32(GetConfig("Iceberg Loot", "Минимум предметов в ящике", 3));
ConfigFile.icebergCrateMaxItems = Convert.ToInt32(GetConfig("Iceberg Loot", "Максимум предметов в ящике", 5));
ConfigFile.floatingCratesToSpawn = Convert.ToInt32(GetConfig("Floating Crates", "Кол-во плавающих ящиков", 7));
ConfigFile.floatingCratesRadius = Convert.ToSingle(GetConfig("Floating Crates", "Радиус зоны плавающих ящиков", 30f));
ConfigFile.floatingCrateDespawnTime = Convert.ToSingle(GetConfig("Floating Crates", "Время исчезновения плавающих ящиков", 900f));
ConfigFile.floatingCrateMinItems = Convert.ToInt32(GetConfig("Floating Crates", "Минимум предметов в ящике", 4));
ConfigFile.floatingCrateMaxItems = Convert.ToInt32(GetConfig("Floating Crates", "Максимум предметов в ящике", 6));
ConfigFile.debisToSpawn = Convert.ToInt32(GetConfig("Debris", "Хлам для спавна", 4));
ConfigFile.lootPerDebris = Convert.ToInt32(GetConfig("Debris", "Добыча за 1 хлам", 1));
ConfigFile.icebergNPCToSpawn = Convert.ToInt32(GetConfig("NPCs", "Кол-во NPC на Айсберге", 5));
ConfigFile.killBoatScientists = Convert.ToBoolean(GetConfig("NPCs", "Уничтожить лодку с Титаника", true));
ConfigFile.icebergNPCSpawnRadius = Convert.ToSingle(GetConfig("NPCs", "Зона спавна NPC на Айсберге", 10f));
ConfigFile.icebergNPCType = Convert.ToString(GetConfig("NPCs", "Тип NPC на Айсберге", "assets/prefabs/npc/scientist/scientist.prefab"));
ConfigFile.icebergNPCNames = Convert.ToString(GetConfig("NPCs", "Имя NPC с Айсберга", "Pirate"));
ConfigFile.boatExhaustFlames = Convert.ToBoolean(GetConfig("Visuals", "Пламя из выхлопной трубы", false));
ConfigFile.boatRotatingLights = Convert.ToBoolean(GetConfig("Visuals", "Вращающиеся сигнальные огни", true));
ConfigFile.disableExtraEffects = Convert.ToBoolean(GetConfig("Visuals", "Отключить все супер эффекты", false));
ConfigFile.boatHornInterval = Convert.ToSingle(GetConfig("Visuals", "Интервал гудков", 20f));
ConfigFile.minRandomEventTime = Convert.ToSingle(GetConfig("Timer Settings", "Минимальное время вызова ивента(сек)", 9000f));
ConfigFile.maxRandomEventTime = Convert.ToSingle(GetConfig("Timer Settings", "Максимальное время вызова ивента(сек)", 10800f));
ConfigFile.randomEventEnabled = Convert.ToBoolean(GetConfig("Timer Settings", "Рандом спавн в промежуток времени", true));
ConfigFile.minPlayersForEvent = Convert.ToInt32(GetConfig("Timer Settings", "Минимальный онлайн на сервере", 1));
ConfigFile.targetIcebergMarkerEnabled = Convert.ToBoolean(GetConfig("Marker Settings", "Точка крушения на карте", true));
ConfigFile.targetIcebergMarkerRadius = Convert.ToSingle(GetConfig("Marker Settings", "Радиус места крушения", 1f));
ConfigFile.targetIcerbergText = Convert.ToString(GetConfig("Marker Settings", "Название места крушения", "Предположительное место крушения"));
if (!Changed) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig()
{
Config.Clear();
LoadVariables();
}
private DynamicConfigFile floatingCrateFile;
private DynamicConfigFile icebergCrateFile;
StoredData storedData;
private class StoredData
{
public List<ItemInfo> lootTable = new List<ItemInfo>();
}
private class ItemInfo
{
public string itemName;
public int minItemAmount;
public int maxItemAmount;
public float chance;
public ulong skinID;
}
void SaveData()
{
storedData.lootTable = floatingCrateTable;
floatingCrateFile.WriteObject(storedData);
storedData.lootTable = icebergCrateTable;
icebergCrateFile.WriteObject(storedData);
}
void LoadData()
{
try
{
bool dataChanged = false;
floatingCrateFile = Interface.Oxide.DataFileSystem.GetFile("RustTanic/FloatingCrates");
storedData = floatingCrateFile.ReadObject<StoredData>();
floatingCrateTable = storedData.lootTable;
if (floatingCrateTable.Count == 0)
{
floatingCrateTable = new List<ItemInfo>
{
new ItemInfo {
itemName = "rope", minItemAmount = 2, maxItemAmount = 4, chance = 1f
},
new ItemInfo {
itemName = "metalblade", minItemAmount = 1, maxItemAmount = 3, chance = 1f
},
new ItemInfo {
itemName = "metalspring", minItemAmount = 1, maxItemAmount = 2, chance = 0.8f
},
new ItemInfo {
itemName = "scrap", minItemAmount = 10, maxItemAmount = 15, chance = 1f
},
new ItemInfo {
itemName = "sheetmetal", minItemAmount = 1, maxItemAmount = 2, chance = 1f
},
new ItemInfo {
itemName = "sewingkit", minItemAmount = 2, maxItemAmount = 4, chance = 1f
},
new ItemInfo {
itemName = "propanetank", minItemAmount = 1, maxItemAmount = 1, chance = 1f
},
new ItemInfo {
itemName = "pistol.revolver", minItemAmount = 1, maxItemAmount = 1, chance = 0.5f
},
new ItemInfo {
itemName = "gears", minItemAmount = 1, maxItemAmount = 3, chance = 0.8f
},
new ItemInfo {
itemName = "roadsigns", minItemAmount = 2, maxItemAmount = 5, chance = 1f
},
};
dataChanged = true;
}
icebergCrateFile = Interface.Oxide.DataFileSystem.GetFile("RustTanic/IcebergCrates");
storedData = icebergCrateFile.ReadObject<StoredData>();
icebergCrateTable = storedData.lootTable;
if (icebergCrateTable.Count == 0)
{
icebergCrateTable = new List<ItemInfo>
{
new ItemInfo {
itemName = "targeting.computer", minItemAmount = 1, maxItemAmount = 1, chance = 0.7f
},
new ItemInfo {
itemName = "techparts", minItemAmount = 1, maxItemAmount = 2, chance = 0.8f
},
new ItemInfo {
itemName = "scrap", minItemAmount = 20, maxItemAmount = 25, chance = 1f
},
new ItemInfo {
itemName = "metal.refined", minItemAmount = 10, maxItemAmount = 20, chance = 1f
},
new ItemInfo {
itemName = "metalpipe", minItemAmount = 1, maxItemAmount = 3, chance = 1f
},
new ItemInfo {
itemName = "heavy.plate.helmet", minItemAmount = 1, maxItemAmount = 1, chance = 0.5f
},
new ItemInfo {
itemName = "heavy.plate.jacket", minItemAmount = 1, maxItemAmount = 1, chance = 0.5f
},
new ItemInfo {
itemName = "heavy.plate.pants", minItemAmount = 1, maxItemAmount = 1, chance = 0.5f
},
new ItemInfo {
itemName = "largemedkit", minItemAmount = 1, maxItemAmount = 3, chance = 1f
},
new ItemInfo {
itemName = "shotgun.waterpipe", minItemAmount = 1, maxItemAmount = 1, chance = 0.8f
},
new ItemInfo {
itemName = "axe.salvaged", minItemAmount = 1, maxItemAmount = 1, chance = 0.8f
},
new ItemInfo {
itemName = "icepick.salvaged", minItemAmount = 1, maxItemAmount = 1, chance = 0.8f
},
new ItemInfo {
itemName = "smgbody", minItemAmount = 1, maxItemAmount = 2, chance = 1f
},
new ItemInfo {
itemName = "semibody", minItemAmount = 1, maxItemAmount = 2, chance = 1f
},
new ItemInfo {
itemName = "riflebody", minItemAmount = 1, maxItemAmount = 2, chance = 0.7f
},
new ItemInfo {
itemName = "pistol.semiauto", minItemAmount = 1, maxItemAmount = 1, chance = 0.7f
},
new ItemInfo {
itemName = "ammo.rifle", minItemAmount = 10, maxItemAmount = 25, chance = 1f
},
new ItemInfo {
itemName = "weapon.mod.holosight", minItemAmount = 1, maxItemAmount = 1, chance = 0.7f
},
new ItemInfo {
itemName = "rifle.bolt", minItemAmount = 1, maxItemAmount = 1, chance = 0.5f
},
new ItemInfo {
itemName = "rifle.semiauto", minItemAmount = 1, maxItemAmount = 1, chance = 0.7f
},
new ItemInfo {
itemName = "wall.external.high.stone", minItemAmount = 1, maxItemAmount = 3, chance = 0.9f
},
};
dataChanged = true;
}
if (dataChanged)
{
Puts("Blank spawntables were found...Generating new ones");
SaveData();
}
}
catch
{
Puts("Failed to load data, creating new file");
storedData = new StoredData();
}
}
private void OnServerInitialized()
{
plugin = this;
LoadVariables();
LoadData();
permission.RegisterPermission(permissionNameADMIN, this);
manager = new GameObject().AddComponent<TitanicManager>();
lang.RegisterMessages(new Dictionary<string, string>
{
["No Permission"] = "You are not allowed to use this command",
["ETA Message"] = "На горизонте появился корабль с пиратами! Они захватили ценный груз и хотят его припрятать на нашем острове!\nПоторопись забрать все самое ценное! Прибудет через ~ {0}s",
["Collide Message 1"] = "Пираты не справились с управлением и столкнулись с айсбергом! Поспеши, место крушения ты можешь посмотреть на карте, но будь аккуратней!",
["Collider Message 2"] = "Пираты не справились с управлением и столкнулись с айсбергом! Поспеши на место крушения, но будь аккуратней!",
}, this);
}
private void Unload()
{
UnityEngine.Object.Destroy(manager.gameObject);
}
private class TitanicManager : FacepunchBehaviour
{
private List<GameObject> allIcebergs = new List<GameObject>();
public List<GameObject> targetIcebergs = new List<GameObject>();
public List<Titanic> currentTitanics = new List<Titanic>();
private Dictionary<CargoShip, GameObject> setIcebergs = new Dictionary<CargoShip, GameObject>();
private void Awake()
{
plugin.Puts("Finding all icebergs...");
PopulateAllIcebergs();
if (allIcebergs.Count == 0)
{
plugin.PrintError("No icebergs were found on the map...This plugin is useless and will be disabled until a map with icebergs is found");
Interface.Oxide.UnloadPlugin(plugin.Name);
}
if (ConfigFile.randomEventEnabled) Invoke(TimedEvent, UnityEngine.Random.Range(ConfigFile.minRandomEventTime, ConfigFile.maxRandomEventTime));
plugin.Puts("Marking all viable icebergs...");
StartCoroutine(UpdateViableIcebergs());
InvokeRepeating(() =>
{
UpdateViableIcebergs();
}, 300f, 300f);
}
private void OnDestroy()
{
foreach (Titanic ship in FindObjectsOfType<Titanic>())
{
ship.GetComponent<BaseEntity>()?.Kill();
}
}
private void PopulateAllIcebergs()
{
foreach (GameObject obj in FindObjectsOfType<GameObject>())
{
if (obj.name.Contains("iceberg") && !obj.name.Contains("."))
{
allIcebergs.Add(obj);
}
}
}
private IEnumerator UpdateViableIcebergs()
{
targetIcebergs.Clear();
foreach (GameObject berg in allIcebergs)
{
yield
return new WaitForSeconds(0.01f);
bool viable = true;
RaycastHit[] hits = UnityEngine.Physics.BoxCastAll(berg.transform.position, berg.GetComponent<Collider>().bounds.extents, Vector3.up);
foreach (RaycastHit hit in hits)
{
yield
return new WaitForSeconds(0.01f);
if (ConfigFile.disableIcebergsWithCupboard)
{
if (hit.collider?.GetComponent<BuildingPrivlidge>())
{
viable = false;
break;
}
}
if (ConfigFile.disableIcebergsWithBuilding)
{
if (hit.collider?.GetComponent<BuildingBlock>())
{
viable = false;
break;
}
}
}
if (viable == true) targetIcebergs.Add(berg);
if (ConfigFile.debugMode)
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
yield
return new WaitForSeconds(0.01f);
if (player.IsAdmin)
{
if (viable == true) player.SendConsoleCommand("ddraw.text", 60f, Color.green, berg.transform.position + new Vector3(0, 50, 0), $"{berg.name} (Viable)");
else player.SendConsoleCommand("ddraw.text", 60f, Color.red, berg.transform.position + new Vector3(0, 50, 0), $"{berg.name} (Not Viable)");
}
}
}
}
plugin.Puts($"{targetIcebergs.Count} viable icebergs were found");
}
public void TimedEvent()
{
if (BasePlayer.activePlayerList.Count < ConfigFile.minPlayersForEvent) return;
SpawnTitanic();
Invoke(TimedEvent, UnityEngine.Random.Range(ConfigFile.minRandomEventTime, ConfigFile.maxRandomEventTime));
}
public void SpawnNearestIceberg(Vector3 pos)
{
GameObject nearest = null;
float currentDistance = float.PositiveInfinity;
foreach (GameObject obj in targetIcebergs)
{
float dist = Vector3.Distance(obj.transform.position, pos);
if (dist < currentDistance)
{
nearest = obj;
currentDistance = dist;
}
}
SpawnTitanic(nearest);
}
public void SpawnTitanic(GameObject targetIceberg = null)
{
CargoShip ship = GameManager.server.CreateEntity("assets/content/vehicles/boats/cargoship/cargoshiptest.prefab", new Vector3(ConVar.Server.worldsize, 0f, ConVar.Server.worldsize),
default(Quaternion), true).GetComponent<CargoShip>();
if (targetIceberg != null) setIcebergs.Add(ship, targetIceberg);
ship.Spawn();
ship.gameObject.AddComponent<Titanic>();
}
public GameObject GetTargetIceberg(CargoShip ship)
{
if (ship != null)
{
GameObject targetBerg = null;
if (setIcebergs.TryGetValue(ship, out targetBerg))
{
setIcebergs.Remove(ship);
return targetBerg;
}
}
int random = UnityEngine.Random.Range(0, targetIcebergs.Count);
if (random >= targetIcebergs.Count) random = targetIcebergs.Count - 1;
if (random < 0) random = 0;
return targetIcebergs[random];
}
}
private class Titanic : FacepunchBehaviour
{
private CargoShip ship;
public GameObject targetIceberg;
private MapMarkerGenericRadius radiusMarker;
private VendingMachineMapMarker textMarker;
private Transform nosePosition;
private Transform exhaust1;
private Transform exhaust2;
private Vector3 collisionPoint;
private Vector3 startSinkingPosition;
private Vector3 halfSinkingPosition;
private Vector3 finishedSinkingPosition;
private List<Vector3> deckExplosionPositions = new List<Vector3>
{
{
new Vector3(-1.9f, 9.5f, 75f)
},
{
new Vector3(3.6f, 9.5f, 67.4f)
},
{
new Vector3(-5.8f, 9.5f, 68.7f)
},
{
new Vector3(-1.2f, 10.8f, 59.7f)
},
{
new Vector3(7.4f, 9.5f, 58.3f)
},
{
new Vector3(-1.2f, 9.5f, 56.7f)
},
{
new Vector3(-7.4f, 9.5f, 58.5f)
},
{
new Vector3(-1.7f, 9.5f, 46.4f)
},
{
new Vector3(-9.3f, 6.5f, 49.7f)
},
{
new Vector3(7.0f, 6.5f, 50.4f)
},
{
new Vector3(2.1f, 9.5f, 32.7f)
},
{
new Vector3(-9.9f, 6.5f, 24.8f)
},
{
new Vector3(-1.7f, 9.5f, 24.4f)
},
{
new Vector3(5.8f, 6.5f, 22.8f)
},
{
new Vector3(-0.9f, 9.5f, 16.5f)
},
{
new Vector3(-0.4f, 9.5f, 4.8f)
},
{
new Vector3(6.1f, 6.5f, -1.7f)
},
{
new Vector3(-8.6f, 6.5f, -3.0f)
},
{
new Vector3(-2.6f, 9.5f, -9.6f)
},
{
new Vector3(-2.9f, 9.5f, -20.9f)
},
{
new Vector3(-1.6f, 9.5f, -27.2f)
},
{
new Vector3(-8.6f, 6.5f, -28.4f)
},
{
new Vector3(5.6f, 6.5f, -28.3f)
},
{
new Vector3(4.4f, 9.5f, -34.9f)
},
{
new Vector3(-6.9f, 9.5f, -34.7f)
},
{
new Vector3(5.5f, 9.5f, -55.3f)
},
{
new Vector3(-10.3f, 9.8f, -54.5f)
},
{
new Vector3(-9.0f, 12.1f, -49.6f)
},
{
new Vector3(6.2f, 12.5f, -49.6f)
},
{
new Vector3(8.7f, 24.5f, -45.5f)
},
{
new Vector3(-12.0f, 25.6f, -45.2f)
},
{
new Vector3(-7.5f, 27.5f, -42.8f)
},
{
new Vector3(3.8f, 27.5f, -44.2f)
},
{
new Vector3(-1.2f, 31.2f, -45.4f)
},
{
new Vector3(-1.5f, 36.5f, -45.6f)
},
};
private List<Vector3> searchLightPositions = new List<Vector3>
{
{
new Vector3(0f, 17.5f, 69.6f)
},
{
new Vector3(-9.8f, 27.5f, -40.5f)
},
{
new Vector3(9.8f, 27.5f, -40.5f)
},
{
new Vector3(-10.7f, 12.5f, -38.8f)
},
{
new Vector3(10.7f, 12.5f, -38.8f)
},
};
private List<BaseEntity> searchLights = new List<BaseEntity>();
private List<BaseEntity> npcs = new List<BaseEntity>();
private List<Transform> shipTransforms = new List<Transform>();
private Coroutine exhaustFireRoutine;
private float tippingSpeed = 0f;
public bool hasCollided;
public bool isTipping = false;
public bool isSinking = false;
public bool isReverseTipping = false;
public bool isFinalSinking = false;
public bool isPaused = false;
private float finalSinkStartTime;
private float pauseEndTime;
private float startTime;
private float startDistance;
private void Awake()
{
ship = GetComponent<CargoShip>();
targetIceberg = plugin.manager.GetTargetIceberg(ship);
InitializeSpawnPosition();
ship.enabled = false;
InitializeTransform(ref nosePosition, new Vector3(0f, 0.5f, 74.1f));
InitializeTransform(ref exhaust1, new Vector3(-2.5f, 32.4f, -53.8f));
InitializeTransform(ref exhaust2, new Vector3(-2.2f, 33f, -52.4f));
transform.LookAt(new Vector3(collisionPoint.x, transform.position.y, collisionPoint.z));
Invoke(SetCollisionPoint, 0.5f);
CancelInvoke(new Action(ship.RespawnLoot));
StartCoroutine(SetHackableCrateTimers());
if (ship.crateSpawns == null || ship.crateSpawns.Count == 0) plugin.PrintError("A CargoShips crateSpawns was null.If you are seeing this error, please report it to redBDGR via the plugin support thread");
SetInitExtraEffects();
startDistance = Vector3.Distance(targetIceberg.transform.position, transform.position);
startTime = UnityEngine.Time.time;
if (targetIceberg == null)
{
plugin.PrintError("Event CargoShip couldn't find a target iceberg.It has been despawned");
ship.Kill();
return;
}
Broadcast(string.Format(plugin.msg("ETA Message"), Mathf.Round(Vector3.Distance(targetIceberg.transform.position, transform.position) / 6.7f)));
if (ConfigFile.targetIcebergMarkerEnabled)
{
radiusMarker = GameManager.server.CreateEntity("assets/prefabs/tools/map/genericradiusmarker.prefab", targetIceberg.transform.position,
default(Quaternion), true).GetComponent<MapMarkerGenericRadius>();
radiusMarker.radius = ConfigFile.targetIcebergMarkerRadius;
radiusMarker.color1 = Color.red;
radiusMarker.alpha = 0.4f;
radiusMarker.Spawn();
radiusMarker.SendUpdate();
textMarker = GameManager.server.CreateEntity("assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab", targetIceberg.transform.position,
default(Quaternion), true).GetComponent<VendingMachineMapMarker>();
textMarker.markerShopName = ConfigFile.targetIcerbergText;
textMarker.Spawn();
}
}
private void OnDestroy()
{
Destroy(nosePosition.gameObject);
foreach (BaseEntity light in searchLights) light.Kill();
if (radiusMarker) radiusMarker.Kill();
if (textMarker) textMarker.Kill();
foreach (BaseEntity ent in npcs) ent.Kill();
}
private void FixedUpdate()
{
if (hasCollided == false)
{
transform.position = Vector3.MoveTowards(transform.position, new Vector3(collisionPoint.x, transform.position.y, collisionPoint.z), 0.2f * ConfigFile.boatSpeed);
if (Vector3.Distance(nosePosition.position, new Vector3(collisionPoint.x, nosePosition.position.y, collisionPoint.z)) < 1f) OnCollideWithIceberg();
return;
}
if (isPaused)
{
if (UnityEngine.Time.time >= pauseEndTime) isPaused = false;
else return;
}
if (isTipping == true)
{
if (exhaust1.position.y < ship.waterLine.position.y)
{
StopCoroutine(exhaustFireRoutine);
}
if (transform.rotation.eulerAngles.z < 20f)
{
transform.Rotate(Quaternion.Euler(0f, 0f, tippingSpeed).eulerAngles);
if (tippingSpeed < 0.1f) tippingSpeed += 0.0001f;
}
if (transform.rotation.eulerAngles.x < 5f)
{
transform.Rotate(Quaternion.Euler(0f, tippingSpeed, 0f).eulerAngles);
}
if (transform.rotation.eulerAngles.z >= 20f && transform.rotation.eulerAngles.y >= 5f) OnFinishTipping();
}
if (isSinking)
{
transform.position = Vector3.MoveTowards(transform.position, halfSinkingPosition, UnityEngine.Time.deltaTime * 0.1f);
if (Vector3.Distance(transform.position, halfSinkingPosition) < 0.1f) OnFinishSinking();
}
if (isReverseTipping)
{
if (transform.rotation.eulerAngles.z > 0f)
{
transform.Rotate(Quaternion.Euler(0f, 0f, -tippingSpeed).eulerAngles);
if (tippingSpeed < 0.1f) tippingSpeed += 0.0001f;
}
if (transform.rotation.eulerAngles.z <= 1f) OnFinishReverseTipping();
}
if (isFinalSinking)
{
if (UnityEngine.Time.time < finalSinkStartTime) { }
transform.position = Vector3.MoveTowards(transform.position, finishedSinkingPosition, UnityEngine.Time.deltaTime * 0.5f);
if (Vector3.Distance(transform.position, finishedSinkingPosition) < 0.5f) StartCoroutine(FinalExplosion());
}
}
private void SetInitExtraEffects()
{
InvokeRepeating(() => ship.ClientRPC(null, "DoHornSound"), ConfigFile.boatHornInterval, ConfigFile.boatHornInterval);
if (ConfigFile.boatExhaustFlames) exhaustFireRoutine = StartCoroutine(FireFromExhaust());
if (ConfigFile.boatRotatingLights) InitSearchLights();
}
private void InitSearchLights()
{
foreach (Vector3 pos in searchLightPositions)
{
BaseEntity ent = GameManager.server.CreateEntity("assets/prefabs/deployable/search light/searchlight.deployed.prefab", ship.transform.TransformPoint(pos), new Quaternion(), true);
ent.Spawn();
ent.SetParent(ship);
ent.transform.localPosition = pos;
ent.gameObject.AddComponent<TitanicSpinningLight>();
searchLights.Add(ent);
}
}
private IEnumerator FireFromExhaust()
{
while (true)
{
yield
return new WaitForSeconds(UnityEngine.Random.Range(0.3f, 0.6f));
BaseEntity ent = GameManager.server.CreateEntity("assets/bundled/prefabs/napalm.prefab", exhaust1.position, new Quaternion(), true);
ent.Spawn();
ent.GetComponent<Rigidbody>().AddForce(UnityEngine.Random.Range(-4, 4), UnityEngine.Random.Range(3, 6), UnityEngine.Random.Range(-4, 4), ForceMode.Impulse);
ent.Invoke(() =>
{
if (ent) ent.Kill();
}, 5f);
}
}
private IEnumerator ExplodeDeck()
{
foreach (Vector3 pos in deckExplosionPositions)
{
if (pos == null) continue;
yield
return new WaitForSeconds(0.01f);
Vector3 _pos = transform.TransformPoint(pos);
Effect.server.Run("assets/prefabs/tools/c4/effects/c4_explosion.prefab", _pos);
if (ConfigFile.disableExtraEffects == false)
{
for (int i = 0; i <= 3; i++)
{
yield
return new WaitForSeconds(0.01f);
string type = UnityEngine.Random.Range(0f, 1f) > 0.5f ? "assets/bundled/prefabs/napalm.prefab" : "assets/bundled/prefabs/oilfireballsmall.prefab";
BaseEntity ent = GameManager.server.CreateEntity(type, _pos, new Quaternion(), true);
ent.Spawn();
ent.GetComponent<Rigidbody>().AddForce(UnityEngine.Random.Range(-4, 4), UnityEngine.Random.Range(3, 6), UnityEngine.Random.Range(-4, 4), ForceMode.Impulse);
ent.Invoke(() =>
{
if (ent) ent.Kill();
}, 7f);
}
BaseEntity ent2 = GameManager.server.CreateEntity("assets/bundled/prefabs/oilfireballsmall.prefab", _pos, new Quaternion(), true);
ent2.Spawn();
}
}
}
private void SetCollisionPoint()
{
RaycastHit[] hits = UnityEngine.Physics.RaycastAll(nosePosition.position, transform.forward, Vector3.Distance(transform.position, targetIceberg.transform.position), plugin.worldLayer);
foreach (RaycastHit hit in hits)
{
Collider col = hit.GetCollider();
if (!col) continue;
if (col.gameObject == targetIceberg) collisionPoint = new Vector3(hit.point.x, nosePosition.position.y, hit.point.z);
}
if (collisionPoint == null || Vector3.Distance(collisionPoint, targetIceberg.transform.position) > 30f)
if (collisionPoint == null || collisionPoint == Vector3.zero) collisionPoint = targetIceberg.GetComponent<Collider>().ClosestPointOnBounds(nosePosition.position);
}
private void OnCollideWithIceberg()
{
hasCollided = true;
isTipping = true;
isSinking = true;
startSinkingPosition = transform.position;
halfSinkingPosition = startSinkingPosition - new Vector3(0f, 20f, 0f);
PauseToLoot(ConfigFile.sequencingGaps);
if (ConfigFile.targetIcebergMarkerEnabled) Broadcast(plugin.msg("Collide Message 1"));
else Broadcast(plugin.msg("Collide Message 2"));
ship.CancelInvoke("DelayedDestroy");
ship.scientistSpawnPoints = new Transform[0];
StartCoroutine(ExplodeDeck());
HandleLoot();
StartCoroutine(HandleNPCs());
ship.StartEgress();
ship.CancelInvoke("UpdateRadiation");
ship.radiation.SetActive(false);
}
private void OnFinishTipping()
{
isTipping = false;
if (isTipping == false && isSinking == false)
{
StartTipCorrection();
}
}
private void OnFinishSinking()
{
isSinking = false;
if (isTipping == false && isSinking == false)
{
StartTipCorrection();
}
}
private void StartTipCorrection()
{
tippingSpeed = 0f;
isReverseTipping = true;
finalSinkStartTime = UnityEngine.Time.time + 120f;
StopCoroutine(exhaustFireRoutine);
}
private void OnFinishReverseTipping()
{
PauseToLoot(ConfigFile.sequencingGaps);
isReverseTipping = false;
isFinalSinking = true;
CancelInvoke(() => ship.ClientRPC(null, "DoHornSound"));
ship.CancelInvoke(ship.PlayHorn);
RaycastHit hit;
if (UnityEngine.Physics.Raycast(transform.position, Vector3.down, out hit, float.PositiveInfinity, 1274232599)) finishedSinkingPosition = hit.point;
else finishedSinkingPosition = transform.position - new Vector3(0, 30f, 0);
}
private IEnumerator FinalExplosion()
{
isFinalSinking = false;
yield
return new WaitForSeconds(ConfigFile.sequencingGaps);
yield
return StartCoroutine(ExplodeDeck());
for (int i = 0; i < ConfigFile.debisToSpawn; i++)
{
yield
return new WaitForSeconds(0.01f);
Vector3 spawnPos = transform.position + (UnityEngine.Random.insideUnitSphere * 10f);
spawnPos.y = TerrainMeta.HeightMap.GetHeight(spawnPos) + 2f;
BaseCombatEntity ent = GameManager.server.CreateEntity("assets/prefabs/npc/m2bradley/bradleyapc.prefab", spawnPos, UnityEngine.Random.rotation, true).GetComponent<BaseCombatEntity>();
ent.Spawn();
ent.GetComponent<BradleyAPC>().maxCratesToSpawn = ConfigFile.lootPerDebris;
ent.Hurt(9999999f, DamageType.Explosion);
}
foreach (RaycastHit entry in UnityEngine.Physics.SphereCastAll(transform.position, 10f, Vector3.up, 10f, plugin.defaultLayer))
{
yield
return new WaitForSeconds(0.01f);
BaseEntity ent = entry.GetEntity();
if (!ent) continue;
HelicopterDebris debris = ent.GetComponent<HelicopterDebris>();
if (debris == null) continue;
plugin.tooHotUntil.SetValue(debris, 0f);
}
if (ship) ship.Kill();
}
private IEnumerator HandleNPCs()
{
if (ConfigFile.killBoatScientists) foreach (HTNPlayer entry in ship.GetComponentsInChildren<HTNPlayer>())
{
yield
return new WaitForSeconds(0.01f);
entry.SetParent(null);
entry.Hurt(entry.health);
}
for (int i = 0; i < ConfigFile.icebergNPCToSpawn; i++)
{
yield
return new WaitForSeconds(0.01f);
RaycastHit hit;
if (UnityEngine.Physics.Raycast(targetIceberg.transform.position + (UnityEngine.Random.insideUnitSphere * ConfigFile.icebergNPCSpawnRadius) + new Vector3(0, 50f, 0), Vector3.down, out hit, float.PositiveInfinity, 1274232599))
{
Vector3 spawnPos = hit.point;
BaseEntity ent = GameManager.server.CreateEntity(ConfigFile.icebergNPCType, spawnPos,
default(Quaternion), true);
ent.Spawn();
npcs.Add(ent);
ent.SetParent(null);
BasePlayer _npcPlayer = ent.GetComponent<BasePlayer>();
if (_npcPlayer) _npcPlayer.displayName = ConfigFile.icebergNPCNames;
}
}
}
private void HandleLoot()
{
ship.RespawnLoot();
StartCoroutine(SetHackableCrateTimers());
StartCoroutine(SpawnIcebergCrates());
StartCoroutine(SpawnFloatingCrates());
ship.CancelInvoke(new Action(ship.PlayHorn));
}
private IEnumerator SpawnIcebergCrates()
{
for (int i = 0; i < ConfigFile.icebergCratesToSpawn; i++)
{
yield
return new WaitForSeconds(0.01f);
RaycastHit hit;
if (UnityEngine.Physics.Raycast(targetIceberg.transform.position + (UnityEngine.Random.insideUnitSphere * ConfigFile.icebergCratesSpawnRadius) + new Vector3(0, 50f, 0), Vector3.down, out hit, float.PositiveInfinity, 1274232599))
{
if (hit.GetEntity())
{
i--;
continue;
}
BaseEntity ent = GameManager.server.CreateEntity(ConfigFile.icebergCratePrefab, hit.point, Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0));
if (ent) ent.Spawn();
StartCoroutine(SpawnItems(ent.GetComponent<StorageContainer>().inventory, plugin.icebergCrateTable, ConfigFile.icebergCrateMinItems, ConfigFile.icebergCrateMaxItems));
ent.Invoke(() =>
{
if (ent) ent.Kill();
}, 600f);
}
}
}
private IEnumerator SpawnFloatingCrates()
{
for (int i = 0; i < ConfigFile.floatingCratesToSpawn; i++)
{
yield
return new WaitForSeconds(0.1f);
Vector3 randomPos = GetRandomOceanRadiusPosition(transform.position, ConfigFile.floatingCratesRadius);
Vector3 spawnPos = new Vector3(randomPos.x, randomPos.y - 30f, randomPos.z);
BaseEntity ent = GameManager.server.CreateEntity("assets/bundled/prefabs/radtown/crate_underwater_advanced.prefab", spawnPos, UnityEngine.Random.rotation, true);
ent.Spawn();
StartCoroutine(SpawnItems(ent.GetComponent<StorageContainer>().inventory, plugin.floatingCrateTable, ConfigFile.floatingCrateMinItems, ConfigFile.floatingCrateMaxItems));
FreeableLootContainer freeable = ent.GetComponent<FreeableLootContainer>();
freeable.GetRB().isKinematic = false;
freeable.buoyancy.enabled = true;
freeable.buoyancy.buoyancyScale = 1f;
freeable.SetFlag(BaseEntity.Flags.Reserved8, false, false);
freeable.Invoke(() =>
{
if (freeable) freeable.Kill();
}, ConfigFile.floatingCrateDespawnTime);
}
}
private IEnumerator SpawnItems(ItemContainer container, List<ItemInfo> table, int min, int max)
{
container.Clear();
int itemsCreated = 0;
int targetAmount = UnityEngine.Random.Range(min, max);
while (itemsCreated < targetAmount)
{
yield
return new WaitForSeconds(0.01f);
ItemInfo data = table[UnityEngine.Random.Range(0, table.Count - 1)];
if (UnityEngine.Random.Range(0, 1) > data.chance)
// ... [Code preview truncated due to length. Full source in attached file] ...