C#:
using System.Collections.Generic;
using Newtonsoft.Json;
using CompanionServer.Handlers;
using UnityEngine;
using Oxide.Core.Plugins;
using Network;
using Rust;
using Rust.Modular;
using System.Collections;
using Newtonsoft.Json.Linq;
using Oxide.Game.Rust.Cui;
using Oxide.Core;
using System;
using Oxide.Plugins.ConvoyExtensionMethods;
using Time = UnityEngine.Time;
using System.Reflection;
using static BaseVehicle;
namespace Oxide.Plugins {
[Info("Convoy", "Adem", "2.4.1")]
class Convoy : RustPlugin {
[PluginReference]
Plugin NpcSpawn, GUIAnnouncements, DiscordMessages, PveMode, Economics, ServerRewards, IQEconomic, DynamicPVP;
#region Variables
const bool en = false;
static Convoy ins;
HashSet<string> subscribeMetods = new HashSet<string> {
"OnCustomNpcTarget", "OnEntitySpawned", "OnEntityTakeDamage", "OnEntityKill", "OnPlayerDeath", "OnEntityDeath", "CanHackCrate", "OnLootEntity", "CanMountEntity", "OnHelicopterRetire", "CanHelicopterTarget", "CanBradleyApcTarget", "OnTurretTarget", "OnExplosiveThrown", "OnCorpsePopulate", "OnCustomNpcTarget", "CanPopulateLoot", "OnCustomLootContainer", "CanEntityTakeDamage", "OnCreateDynamicPVP", "OnBotReSpawnCrateDropped", "CanBradleySpawnNpc", "CanHelicopterSpawnNpc",
}
;
ConvoyController convoyController;
HashSet<ulong> bradleyOrHeliContainers = new HashSet<ulong>();
#endregion Variables
#region API
private bool IsConvoyVehicle(BaseEntity entity) {
if (entity == null || convoyController == null) return false;
return convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value) != null;
}
private bool IsConvoyCrate(HackableLockedCrate crate) {
if (crate == null || convoyController == null) return false;
return convoyController.GetTruckByCrateNetID(crate.net.ID.Value) != null;
}
private bool IsConvoyHeli(PatrolHelicopter patrolHelicopter) {
if (patrolHelicopter == null || patrolHelicopter.net == null) return false;
return convoyController != null && convoyController.IsConvoyHeli(patrolHelicopter.net.ID.Value);
}
#endregion API
#region Hooks
void Init() {
ins = this;
UpdateConfig();
Unsubscribes();
LoadData();
}
void OnServerInitialized() {
if (!NpcManager.CheckNPCSpawn()) {
PrintError("NpcSpawn plugin doesn`t exist! Please read the file ReadMe.txt");
NextTick(() => Server.Command($"o.unload {Name}"));
}
LoadDefaultMessages();
CheckZeroCoord();
ConvoyLauncher.AutoStartEvent();
}
void Unload() {
ConvoyLauncher.StopEvent(true);
RootCar.RootStop();
}
void OnEntitySpawned(LockedByEntCrate crate) {
if (crate == null) return;
if (crate.ShortPrefabName == "bradley_crate") {
ConvoyBradley convoyBradley = convoyController.GetConvoyBradleyAtPosition(crate.transform.position);
if (convoyBradley == null) return;
NextTick(() => LootManager.UpdateConvoyLockedByEntCrate(crate, convoyBradley.bradleyConfig.offDelay, convoyBradley.bradleyConfig.typeLootTable, convoyBradley.bradleyConfig.lootTable));
bradleyOrHeliContainers.Add(crate.net.ID.Value);
}
else if (crate.ShortPrefabName == "heli_crate") {
ConvoyHeli convoyHeli = convoyController.GetCConvoyHeliAtPosition(crate.transform.position);
if (convoyHeli == null) return;
NextTick(() => LootManager.UpdateConvoyLockedByEntCrate(crate, convoyHeli.heliConfig.offDelay, convoyHeli.heliConfig.typeLootTable, convoyHeli.heliConfig.lootTable));
bradleyOrHeliContainers.Add(crate.net.ID.Value);
}
}
void OnEntitySpawned(HelicopterDebris entity) {
if (!entity.IsExists()) return;
if (convoyController.GetConvoyBradleyAtPosition(entity.transform.position) != null || convoyController.GetCConvoyHeliAtPosition(entity.transform.position) != null) {
Rigidbody rigidbody = entity.gameObject.GetComponent<Rigidbody>();
rigidbody.mass = 1;
}
}
object OnTurretTarget(AutoTurret turret, ScientistNPC scientistNPC) {
if (turret == null || scientistNPC == null) return null;
if (NpcManager.IsConvoyNpc(scientistNPC.displayName)) {
if (!_config.enablePlayerTurret) return true;
else if(scientistNPC.isMounted) return true;
else if (!convoyController.IsPlayerTurretCanAttackConvoy(turret)) return true;
}
return null;
}
object OnEntityTakeDamage(BaseVehicleModule baseVehicleModule, HitInfo info) {
if (baseVehicleModule == null || info == null) return null;
BaseModularVehicle modularVehicle = baseVehicleModule.Vehicle;
if (modularVehicle == null || modularVehicle.net == null) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(modularVehicle.net.ID.Value);
if (convoyVehicle == null) return null;
if (convoyController.CanConvoyEntityTakeDamage(info, baseVehicleModule)) {
ConvoyModular convoyModular = convoyVehicle as ConvoyModular;
modularVehicle.health -= convoyModular.supportModularConfig.damageMultiplier * info.damageTypes.Total() / 5;
if (!modularVehicle.IsDestroyed && modularVehicle.health <= 0) modularVehicle.Kill(BaseNetworkable.DestroyMode.Gib);
else {
for (int i = 0; i <= modularVehicle.moduleSockets.Count; i++) {
BaseVehicleModule module;
if (modularVehicle.TryGetModuleAt(i, out module)) module.SetHealth(module._maxHealth * modularVehicle.health / modularVehicle._maxHealth);
}
}
if (info.InitiatorPlayer != null) convoyController.OnConvoyAttacked(info.InitiatorPlayer);
return null;
}
else return true;
}
object OnEntityTakeDamage(ModularCar entity, HitInfo info) {
if (entity == null || info == null || entity.net == null) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value);
if (convoyVehicle == null) return null;
if (convoyController.CanConvoyEntityTakeDamage(info, entity)) {
ConvoyModular convoyModular = convoyVehicle as ConvoyModular;
info.damageTypes.ScaleAll(convoyModular.supportModularConfig.damageMultiplier);
convoyController.OnConvoyAttacked(info.InitiatorPlayer);
return null;
}
else return true;
}
object OnEntityTakeDamage(BasicCar entity, HitInfo info) {
if (entity == null || info == null || entity.net == null) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value);
if (convoyVehicle == null) return null;
if (convoyController.CanConvoyEntityTakeDamage(info, entity)) {
convoyController.OnConvoyAttacked(info.InitiatorPlayer);
return null;
}
else return true;
}
object OnEntityTakeDamage(BradleyAPC entity, HitInfo info) {
if (entity == null || info == null || entity.net == null) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value);
if (convoyVehicle == null) return null;
if (convoyController.CanConvoyEntityTakeDamage(info, entity)) {
if (info.InitiatorPlayer.IsRealPlayer()) convoyController.OnConvoyAttacked(info.InitiatorPlayer);
return null;
}
else return true;
}
object OnEntityTakeDamage(ScientistNPC entity, HitInfo info) {
if (info == null || entity == null || !info.InitiatorPlayer.IsRealPlayer()) return null;
if (NpcManager.IsConvoyNpc(entity.displayName) && convoyController.CanConvoyNpcTakeDamage(info)) {
BaseVehicle baseVehicle = entity.GetMountedVehicle();
if (baseVehicle != null && baseVehicle.IsDriver(entity)) {
ins.NextTick(() => {
if (convoyController != null) convoyController.OnConvoyAttacked(info.InitiatorPlayer);
}
);
return true;
}
ins.NextTick(() => {
if (convoyController != null) convoyController.OnConvoyAttacked(info.InitiatorPlayer);
}
);
return null;
}
return null;
}
object OnEntityTakeDamage(PatrolHelicopter entity, HitInfo info) {
if (entity == null || info == null) return null;
if (IsConvoyHeli(entity) && info.InitiatorPlayer != null) {
if (!convoyController.CanConvoyEntityTakeDamage(info, entity)) {
info.damageTypes.ScaleAll(0);
return true;
}
else {
convoyController.OnConvoyAttacked(info.InitiatorPlayer);
}
}
return null;
}
void OnEntityTakeDamage(BuildingBlock buildingBlock, HitInfo info) {
if (buildingBlock == null || info.PointStart == null) return;
if (info.WeaponPrefab != null && info.WeaponPrefab.name == "MainCannonShell") {
if (!convoyController.convoyVehicles.Any(x => x != null && Vector3.Distance(info.PointStart, x.baseEntity.transform.position) < _config.maxDamageDistance * 2)) return;
info.damageTypes.ScaleAll(100 * _config.bradleyBuildingDamageScale);
return;
}
if (info.Initiator == null || info.Initiator.net == null) return;
BradleyAPC bradley = info.Initiator as BradleyAPC;
if (bradley != null) {
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(bradley.net.ID.Value);
if (convoyVehicle != null) info.damageTypes.ScaleAll(_config.bradleyBuildingDamageScale);
}
}
void OnEntityKill(ModularCar entity) {
if (entity == null || entity.net == null) return;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value);
if (convoyVehicle == null) return;
convoyController.OnConvoyVehicleDie(convoyVehicle);
ConvoyTruck convoyTruck = convoyVehicle as ConvoyTruck;
if (convoyTruck != null) {
if (_config.dropCrateAfterKillTruck) convoyTruck.DropCrate();
else NotifyManager.SendMessageToAll("Failed", ins._config.prefix);
ins.NextTick(convoyController.CheckConvoyHasNoLootedTruck);
}
}
void OnEntityKill(BradleyAPC entity) {
if (entity == null || entity.net == null) return;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value);
if (convoyVehicle == null) return;
convoyController.OnConvoyVehicleDie(convoyVehicle);
ConvoyBradley convoyBradley = convoyVehicle as ConvoyBradley;
if (ins._config.pveMode.pve && ins.plugins.Exists("PveMode")) {
timer.In(1f, () => {
ins.PveMode.Call("EventAddCrates", ins.Name, ins.bradleyOrHeliContainers);
ins.bradleyOrHeliContainers.Clear();
}
);
}
}
void OnEntityKill(BasicCar entity) {
if (entity == null || entity.net == null) return;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(entity.net.ID.Value);
if (convoyVehicle == null) return;
convoyController.OnConvoyVehicleDie(convoyVehicle);
}
void OnEntityKill(PatrolHelicopter entity) {
if (entity == null) return;
if (!IsConvoyHeli(entity)) return;
if (_config.pveMode.pve && plugins.Exists("PveMode")) {
timer.In(1f, () => {
PveMode.Call("EventAddCrates", Name, bradleyOrHeliContainers);
ins.bradleyOrHeliContainers.Clear();
}
);
}
}
void OnEntityKill(ScientistNPC scientistNPC) {
if (scientistNPC == null || scientistNPC.net == null || !NpcManager.IsConvoyNpc(scientistNPC.displayName) || scientistNPC.isMounted) return;
if (ins._config.blockSpawnDieNpc) {
ConvoyVehicle convoyVehicle = convoyController.convoyVehicles.FirstOrDefault(x => x != null && x.roamNpcsNetIDs.Any(y => y == scientistNPC.net.ID.Value));
if (convoyVehicle != null) convoyVehicle.countDieNpc++;
}
if (convoyController.IsConvoyStop() && _config.needKillNpc) {
convoyController.roamNpc.Remove(scientistNPC);
if (convoyController.roamNpc.Count == 0) {
NotifyManager.SendMessageToAll("SecurityNpcKill", _config.prefix);
}
}
}
void OnPlayerDeath(BasePlayer player, HitInfo info) {
if (player == null) return;
if (ZoneController.IsPlayerInZone(player.userID)) ZoneController.OnPlayerLeaveZone(player);
}
void OnEntityDeath(ModularCar entity, HitInfo info) {
if (entity == null || entity.net == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
EconomyManager.CheckIfPlayerKillConvoyVehicle(entity.net.ID.Value, "Modular", info.InitiatorPlayer);
}
void OnEntityDeath(BradleyAPC entity, HitInfo info) {
if (entity == null || entity.net == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
EconomyManager.CheckIfPlayerKillConvoyVehicle(entity.net.ID.Value, "Bradley", info.InitiatorPlayer);
}
void OnEntityDeath(BasicCar entity, HitInfo info) {
if (entity == null || entity.net == null || info == null || !info.InitiatorPlayer.IsRealPlayer()) return;
EconomyManager.CheckIfPlayerKillConvoyVehicle(entity.net.ID.Value, "Sedan", info.InitiatorPlayer);
}
void OnEntityDeath(PatrolHelicopter entity, HitInfo info) {
if (entity == null || info == null || info.InitiatorPlayer == null) return;
if (IsConvoyHeli(entity)) EconomyManager.ActionEconomy(info.InitiatorPlayer.userID, "Heli");
}
void OnEntityDeath(ScientistNPC scientistNPC, HitInfo info) {
if (scientistNPC == null || scientistNPC.net == null || !NpcManager.IsConvoyNpc(scientistNPC.displayName)) return;
if (info != null && info.InitiatorPlayer.IsRealPlayer()) EconomyManager.ActionEconomy(info.InitiatorPlayer.userID, "Npc");
}
object CanHackCrate(BasePlayer player, HackableLockedCrate crate) {
if (crate == null || player == null) return null;
ConvoyTruck convoyTruck = convoyController.GetTruckByCrateNetID(crate.net.ID.Value);
if (convoyTruck == null) return null;
if (player.InSafeZone()) return true;
else if ((!_config.needStopConvoy || convoyController.IsConvoyStop()) && (!_config.needKillCars || !convoyController.ConvoyHaveAnySecurityVehivcle()) && (!_config.needKillNpc || !convoyController.roamNpc.Any(x => x.IsExists()))) {
if (_config.pveMode.pve && plugins.Exists("PveMode") && !_config.pveMode.hackCrate && PveMode.Call("CanActionEvent", Name, player) != null) return true;
NotifyManager.SendMessageToAll("StartHackCrate", _config.prefix, player.displayName);
convoyController.OnConvoyAttacked(player);
convoyTruck.UpdateCrateHackTimeWithDelay();
return null;
}
else {
NotifyManager.SendMessageToPlayer(player, "CantHackCrate", _config.prefix);
return true;
}
}
void OnLootEntity(BasePlayer player, HackableLockedCrate crate) {
if (player == null || crate == null || crate.net == null) return;
ConvoyTruck convoyTruck = convoyController.GetTruckByCrateNetID(crate.net.ID.Value);
if (convoyTruck != null) convoyController.OnCrateLooted(crate.net.ID.Value);
}
object CanMountEntity(BasePlayer player, BaseMountable entity) {
if (!player.IsRealPlayer() || entity == null) return null;
BaseEntity vehicle = entity.VehicleParent();
if (vehicle != null & IsConvoyVehicle(vehicle)) return true;
return null;
}
object OnHelicopterRetire(PatrolHelicopterAI ai) {
if (convoyController.convoyHeli != null && convoyController.convoyHeli.patrolHelicopterAI == ai) return true;
return null;
}
object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player) {
if (heli == null || heli.helicopterBase == null) return null;
if (IsConvoyHeli(heli.helicopterBase)) {
if (!player.IsRealPlayer() || player.IsSleeping()) return false;
else if (!_config.isAggressive && !convoyController.IsConvoyStop() && !convoyController.IsAnyCrateHacking()) return false;
}
return null;
}
object CanBradleyApcTarget(BradleyAPC apc, BaseEntity entity) {
if (apc == null || entity == null || apc.net == null) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(apc.net.ID.Value);
if (convoyVehicle == null) return null;
if (!_config.isAggressive && !convoyController.IsConvoyStop() && !convoyController.IsAnyCrateHacking()) return false;
BasePlayer player = entity as BasePlayer;
if (!player.IsRealPlayer() || player.IsSleeping() || player.InSafeZone()) return false;
return null;
}
void OnExplosiveThrown(BasePlayer player, BaseEntity entity, ThrownWeapon item) {
if (!player.IsRealPlayer()) return;
if (convoyController.convoyVehicles.Any(x => x != null && x.baseEntity != null && Vector3.Distance(player.transform.position, x.baseEntity.transform.position) < 25f)) convoyController.OnConvoyAttacked(player);
}
void OnCorpsePopulate(ScientistNPC scientistNPC, NPCPlayerCorpse corpse) {
if (scientistNPC == null || corpse == null) return;
NpcConfig npcConfig = NpcManager.GetNpcConfigByDisplayName(scientistNPC.displayName);
if (npcConfig == null) return;
NextTick(() => {
if (corpse != null) LootManager.UpdateNpcLootContainer(corpse, npcConfig);
}
);
}
#region OtherPLugins
object OnCustomNpcTarget(ScientistNPC npc, BasePlayer player) {
if (convoyController == null || npc == null) return null;
if (!convoyController.IsConvoyStop() && !_config.isAggressive && NpcManager.IsConvoyNpc(npc.displayName)) return false;
return null;
}
object CanPopulateLoot(LootContainer container) {
if (convoyController == null || container == null) return null;
if (container is HackableLockedCrate) {
ConvoyTruck convoyTruck = convoyController.GetTruckByCrateNetID(container.net.ID.Value);
if (convoyTruck == null) return null;
if (convoyTruck.modularConfig.typeLootTable == 2) return null;
else return true;
}
else if (container.ShortPrefabName == "bradley_crate") {
ConvoyBradley convoyBradley = convoyController.GetConvoyBradleyAtPosition(container.transform.position);
if (convoyBradley == null) return null;
if (convoyBradley.bradleyConfig.typeLootTable == 2) return null;
else return true;
}
else if (container.ShortPrefabName == "heli_crate") {
ConvoyHeli convoyHeli = convoyController.GetCConvoyHeliAtPosition(container.transform.position);
if (convoyHeli == null) return null;
if (convoyHeli.heliConfig.typeLootTable == 2) return null;
else return true;
}
else return null;
}
object CanPopulateLoot(ScientistNPC scientistNPC, NPCPlayerCorpse corpse) {
if (convoyController == null || scientistNPC == null || corpse == null || convoyController.convoyVehicles.Count == 0) return null;
if (convoyController.convoyVehicles.Any(x => x != null && x.scientists.Contains(scientistNPC))) {
NpcConfig npcConfig = _config.NPC.FirstOrDefault(x => x.name == scientistNPC.name);
if (npcConfig == null) return null;
if (npcConfig.typeLootTable == 2) return null;
else return true;
}
return null;
}
object OnCustomLootContainer(NetworkableId netID) {
if (convoyController == null || netID == null) return null;
ConvoyTruck convoyTruck = convoyController.GetTruckByCrateNetID(netID.Value);
if (convoyTruck == null) return null;
if (convoyTruck.modularConfig.typeLootTable != 3) return true;
return null;
}
object CanEntityBeTargeted(ScientistNPC scientistNPC, AutoTurret turret) {
if (turret == null || scientistNPC == null) return null;
if (NpcManager.IsConvoyNpc(scientistNPC.displayName)) {
if (!_config.enablePlayerTurret) return false;
if (scientistNPC.isMounted) return false;
else if (!convoyController.IsPlayerTurretCanAttackConvoy(turret)) return false;
}
return null;
}
object CanEntityTakeDamage(BasePlayer victim, HitInfo hitinfo) {
if (convoyController == null || !_config.eventZone.isCreateZonePVP || hitinfo == null || !victim.IsRealPlayer()) return null;
if (ZoneController.IsPlayerInZone(victim.userID) && hitinfo.InitiatorPlayer.IsRealPlayer() && ZoneController.IsPlayerInZone(hitinfo.InitiatorPlayer.userID)) return true;
else return null;
}
object CanEntityTakeDamage(ScientistNPC entity, HitInfo info) {
if (info == null || entity == null || !info.InitiatorPlayer.IsRealPlayer()) return null;
if (NpcManager.IsConvoyNpc(entity.displayName) && convoyController.CanConvoyNpcTakeDamage(info)) {
BaseVehicle baseVehicle = entity.GetMountedVehicle();
if (baseVehicle != null && baseVehicle.IsDriver(entity)) {
convoyController.OnConvoyAttacked(info.InitiatorPlayer);
return false;
}
convoyController.OnConvoyAttacked(info.InitiatorPlayer);
return null;
}
return null;
}
object CanEntityTakeDamage(BasicCar victim, HitInfo hitinfo) {
if (convoyController == null || victim == null || hitinfo == null) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(victim.net.ID.Value);
if (convoyVehicle == null) return null;
if (convoyController.CanConvoyEntityTakeDamage(hitinfo, victim)) return true;
else return false;
}
object CanEntityTakeDamage(ModularCar victim, HitInfo hitinfo) {
if (convoyController == null || victim == null || victim.net == null || hitinfo == null || !hitinfo.InitiatorPlayer.IsRealPlayer()) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(victim.net.ID.Value);
if (convoyVehicle == null) return null;
if (!PveModeAllowAction(hitinfo.InitiatorPlayer)) return false;
return true;
}
object CanEntityTakeDamage(CustomBradley victim, HitInfo hitinfo) {
if (convoyController == null || victim == null || victim.net == null || hitinfo == null || !hitinfo.InitiatorPlayer.IsRealPlayer()) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(victim.net.ID.Value);
if (convoyVehicle != null) return true;
return null;
}
object CanEntityTakeDamage(BaseVehicleModule baseVehicleModule, HitInfo hitinfo) {
if (convoyController == null || baseVehicleModule == null || baseVehicleModule.Vehicle == null || baseVehicleModule.Vehicle.net == null || hitinfo == null || !hitinfo.InitiatorPlayer.IsRealPlayer()) return null;
ConvoyVehicle convoyVehicle = convoyController.GetConvoyVehicleByEntityNetId(baseVehicleModule.Vehicle.net.ID.Value);
if (convoyVehicle == null) return null;
if (!PveModeAllowAction(hitinfo.InitiatorPlayer)) return false;
return true;
}
object CanEntityTakeDamage(PatrolHelicopter entity, HitInfo hitinfo) {
if (entity == null || hitinfo == null) return null;
if (IsConvoyHeli(entity) && hitinfo.InitiatorPlayer != null) {
if (!convoyController.CanConvoyEntityTakeDamage(hitinfo, entity)) return false;
}
return null;
}
object OnCreateDynamicPVP(string eventName, BradleyAPC entity) {
if (convoyController == null || entity == null) return null;
if (IsConvoyVehicle(entity)) return true;
return null;
}
object OnCreateDynamicPVP(string eventName, PatrolHelicopter entity) {
if (convoyController == null || entity == null) return null;
if (IsConvoyHeli(entity)) return true;
return null;
}
object OnBotReSpawnCrateDropped(HackableLockedCrate crate) {
if (convoyController == null || crate == null || crate.net == null) return null;
if (IsConvoyCrate(crate)) return true;
return null;
}
object CanBradleySpawnNpc(BradleyAPC bradley) {
if (convoyController == null || _config.betterNpcConfig.bradleyNpc || bradley == null || bradley.net == null) return null;
if (convoyController.GetConvoyVehicleByEntityNetId(bradley.net.ID.Value) != null) return true;
return null;
}
object CanHelicopterSpawnNpc(PatrolHelicopter helicopter) {
if (convoyController == null || _config.betterNpcConfig.heliNpc || helicopter == null) return null;
if (IsConvoyHeli(helicopter)) return true;
return null;
}
private object OnRestoreUponDeath(BasePlayer player) {
if (player == null) return null;
if (_config.eventZone.blockRestoreUponDeath && ZoneController.IsPlayerInZone(player.userID)) return false;
return null;
}
#endregion OtherPLugins
#endregion Hooks
#region Commands
[ChatCommand("convoystart")]
void StartCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
if (arg != null && arg.Length >= 1) ConvoyLauncher.StartEvent(player, arg[0]);
else ConvoyLauncher.StartEvent(player);
}
[ChatCommand("convoystop")]
void StopCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
ConvoyLauncher.StopEvent();
}
[ConsoleCommand("convoystart")]
void ConsoleStartCommand(ConsoleSystem.Arg arg) {
if (arg.Player() != null) return;
if (arg.Args != null && arg.Args.Length > 0) ConvoyLauncher.StartEvent(null, arg.Args[0]);
ConvoyLauncher.StartEvent();
Puts("Event activated");
}
[ConsoleCommand("convoystop")]
void ConsoleStopCommand(ConsoleSystem.Arg arg) {
if (arg.Player() == null) ConvoyLauncher.StopEvent();
}
[ChatCommand("convoyrootstart")]
void RootStartCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin || player.isInAir) return;
RootCar.CreateRootCar(player);
}
[ChatCommand("convoyrootstop")]
void RootStopCommand(BasePlayer player, string command, string[] arg) {
if (player.IsAdmin) RootCar.RootStop();
}
[ChatCommand("convoyrootsave")]
void RootSaveCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin) return;
if (arg == null || arg.Length == 0) {
NotifyManager.SendMessageToPlayer(player, $"{_config.prefix} To save the route, use the command: <color=#738d43>convoyrootsave [rootpresetname]</color>");
return;
}
RootCar.SaveRoot(player, arg[0]);
}
[ChatCommand("convoyroadblock")]
void RoadBlockCommand(BasePlayer player, string command, string[] arg) {
if (!player.IsAdmin || player.isInAir) return;
PathList blockRoad = TerrainMeta.Path.Roads.FirstOrDefault(x => x.Path.Points.Any(y => Vector3.Distance(player.transform.position, y) < 10));
if (blockRoad == null) NotifyManager.SendMessageToPlayer(player, $"{_config.prefix} Road not found <color=#ce3f27>not found</color>");
int index = TerrainMeta.Path.Roads.IndexOf(blockRoad);
if (_config.blockRoads.Contains(index)) NotifyManager.SendMessageToPlayer(player, $"{_config.prefix} The road is already <color=#ce3f27>blocked</color>");
else if (blockRoad != null) {
_config.blockRoads.Add(index);
SaveConfig();
NotifyManager.SendMessageToPlayer(player, $"{_config.prefix} The road with the index <color=#738d43>{index}</color> is <color=#ce3f27>blocked</color>");
}
}
#endregion Commands
#region Method
void UpdateConfig() {
if (_config.version != Version.ToString()) {
VersionNumber versionNumber;
var versionArray = _config.version.Split('.');
versionNumber.Major = Convert.ToInt32(versionArray[0]);
versionNumber.Minor = Convert.ToInt32(versionArray[1]);
versionNumber.Patch = Convert.ToInt32(versionArray[2]);
if (versionNumber.Major == 2) {
if (versionNumber.Minor == 0) {
if (versionNumber.Patch == 0) {
foreach (ConvoySetting convoySetting in _config.convoys) convoySetting.displayName = "Convoy";
}
if (versionNumber.Patch <= 7) {
foreach (NpcConfig npcConfig in _config.NPC) npcConfig.kit = "";
}
if (versionNumber.Patch <= 9) {
_config.autoEvent = true;
}
versionNumber.Minor = 1;
versionNumber.Patch = 0;
}
if (versionNumber.Minor == 1) {
if (versionNumber.Patch <= 5) {
if (!_config.barriers.Contains("xmasportalentry")) {
_config.barriers.Add("xmasportalentry");
}
}
if (versionNumber.Patch < 7) {
if (!_config.barriers.Contains("stone-ore")) _config.barriers.Add("stone-ore");
if (!_config.barriers.Contains("metal-ore")) _config.barriers.Add("metal-ore");
if (!_config.barriers.Contains("sulfur-ore")) _config.barriers.Add("sulfur-ore");
}
if (versionNumber.Patch <= 9) {
_config.pveMode.scaleDamage.Add(new ScaleDamageConfig {
Type = "Helicopter", Scale = 1
}
);
}
versionNumber.Minor = 2;
versionNumber.Patch = 0;
}
if (versionNumber.Minor == 2) {
if (versionNumber.Patch == 0) {
PrintWarning("Some parameters in the config have been changed due to the addition of new functions!\nRead the changelog!");
_config.roadLength = 300;
_config.killConvoyAfterLoot = true;
_config.bradleyBuildingDamageScale = 1f;
_config.killTimeConvoyAfterLoot = 300;
_config.isAggressive = true;
_config.timeNotifications = new HashSet<int> {
300, 60, 30, 5
}
;
for (int i = 0; i < _config.convoys.Count; i++) {
ConvoySetting convoySetting = _config.convoys[i];
convoySetting.speed = 5f;
if (convoySetting.name.Contains("hard")) {
convoySetting.vehiclesOrder = new List<string> {
"bradley_1", "modular_1", "sedan_1", "truck_1", "sedan_1", "modular_1", "bradley_1"
}
;
}
else {
convoySetting.vehiclesOrder = new List<string> {
"bradley_1", "sedan_1", "truck_1", "sedan_1", "bradley_1"
}
;
}
}
for (int i = 0; i < _config.modularConfiguration.Count; i++) {
ModularConfig modularConfig = _config.modularConfiguration[i];
modularConfig.changeUnlockTime = true;
}
for (int i = 0; i < _config.NPC.Count; i++) {
NpcConfig npcConfig = _config.NPC[i];
npcConfig.turretDamageScale = 1;
for (int a = 0; a < npcConfig.beltItems.Count; a++) {
NpcBelt npcBelt = npcConfig.beltItems[a];
npcBelt.ammo = "";
}
}
}
if (versionNumber.Patch < 9) {
_config.marker.useRingMarker = true;
_config.marker.useShopMarker = true;
}
versionNumber.Minor = 3;
versionNumber.Patch = 0;
}
if (versionNumber.Minor == 3) {
if (versionNumber.Patch == 0) {
foreach (SupportModularConfig supportModularConfig in _config.supportModularConfiguration) supportModularConfig.frontVehicleDistance = 10;
foreach (SedanConfig sedanConfig in _config.sedanConfiguration) sedanConfig.frontVehicleDistance = 10;
foreach (ModularConfig modularConfig in _config.modularConfiguration) modularConfig.frontVehicleDistance = 10;
foreach (BradleyConfig bradleyConfig in _config.bradleyConfiguration) bradleyConfig.frontVehicleDistance = 10;
_config.pveMode.showEventOwnerNameOnMap = true;
}
if (versionNumber.Patch <= 4) {
foreach (SupportModularConfig supportModularConfig in _config.supportModularConfiguration) supportModularConfig.numberOfNpc = 4;
foreach (SedanConfig sedanConfig in _config.sedanConfiguration) sedanConfig.numberOfNpc = 4;
foreach (ModularConfig modularConfig in _config.modularConfiguration) modularConfig.numberOfNpc = 4;
foreach (BradleyConfig bradleyConfig in _config.bradleyConfiguration) bradleyConfig.numberOfNpc = 6;
}
if (versionNumber.Patch <= 7) {
foreach (HeliConfig heliConfig in _config.heliesConfiguration) {
heliConfig.outsideTime = 30;
}
}
versionNumber.Minor = 4;
versionNumber.Patch = 0;
}
if (versionNumber.Minor == 4) {
if (versionNumber.Patch == 0) {
_config.enablePlayerTurret = true;
}
}
}
else {
PrintError("Delete the configuration file!");
NextTick(() => Server.Command($"o.unload {Name}"));
return;
}
_config.version = Version.ToString();
SaveConfig();
}
}
void Unsubscribes() {
foreach (string hook in subscribeMetods) Unsubscribe(hook);
}
void Subscribes() {
foreach (string hook in subscribeMetods) Subscribe(hook);
}
void CheckZeroCoord() {
foreach (Collider collider in UnityEngine.Physics.OverlapSphere(Vector3.zero, 3f)) {
BaseEntity entity = collider.ToBaseEntity();
if (entity == null) continue;
if (entity.PrefabName.Contains("modular") || entity.PrefabName.Contains("locked")) entity.Kill();
}
}
bool PveModeAllowAction(BasePlayer player) {
if (!ins.plugins.Exists("PveMode") || !plugins.Exists("PveMode")) return true;
if (ins.PveMode.Call("CanActionEvent", ins.Name, player) != null) return false;
return true;
}
void CopySerializableFields<T>(T src, T dst) {
FieldInfo[] srcFields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo field in srcFields) {
object value = field.GetValue(src);
field.SetValue(dst, value);
}
}
#endregion Method
#region Classes
static class ConvoyLauncher {
static Coroutine autoEventCoroutine;
internal static void AutoStartEvent() {
if (!ins._config.autoEvent) return;
if (autoEventCoroutine != null) return;
autoEventCoroutine = ServerMgr.Instance.StartCoroutine(AutoEventCorountine());
}
static IEnumerator AutoEventCorountine() {
yield return CoroutineEx.waitForSeconds(UnityEngine.Random.Range(ins._config.minTimeBetweenEvent, ins._config.maxTimeBetweenEvent));
StartEvent();
}
internal static void StartEvent(BasePlayer initiator = null, string presetName = "") {
if (ins.convoyController != null) {
NotifyManager.PrintError(initiator, "EventActive_Exeption");
return;
}
ConvoySetting convoysetting = DefineEventConfig(presetName);
if (convoysetting == null) {
NotifyManager.PrintError(initiator, "СonfigurationNotFound_Exeption");
StopEvent();
return;
}
ConvoyPath convoyPath = ConvoyPath.DefineConvoyPath(convoysetting.vehiclesOrder.Count);
if (convoyPath == null) {
NotifyManager.PrintError(initiator, "RootNotFound_Exeption", convoysetting.name);
StopEvent();
return;
}
if (autoEventCoroutine != null) {
ServerMgr.Instance.StopCoroutine(autoEventCoroutine);
autoEventCoroutine = null;
}
GameObject gameObject = new GameObject();
ins.convoyController = gameObject.AddComponent<ConvoyController>();
ins.convoyController.Init(convoysetting, convoyPath);
}
static ConvoySetting DefineEventConfig(string eventPresetName) {
if (eventPresetName != "") {
return ins._config.convoys.FirstOrDefault(x => x.name == eventPresetName);
}
else {
if (!ins._config.convoys.Any(x => x.on && x.chance != 0)) return null;
float sumChance = 0;
foreach (ConvoySetting eventConfig in ins._config.convoys) {
if (eventConfig.on) sumChance += eventConfig.chance;
}
float random = UnityEngine.Random.Range(0, sumChance);
foreach (ConvoySetting eventConfig in ins._config.convoys) {
if (eventConfig.on) {
random -= eventConfig.chance;
if (random <= 0) return eventConfig;
}
}
return null;
}
}
internal static void StopEvent(bool isPluginUnloading = false) {
if (ins.convoyController != null) {
ins.Unsubscribes();
GameObject.Destroy(ins.convoyController.gameObject);
ZoneController.ClearZoneData();
EconomyManager.SendBalance();
NotifyManager.SendMessageToAll("Finish", ins._config.prefix);
Interface.CallHook("OnConvoyStop");
if (ins._config.enableStartStopLogs) NotifyManager.PrintLogMessage("EventStop_Log");
}
if (!isPluginUnloading) AutoStartEvent();
else if (autoEventCoroutine != null) ServerMgr.Instance.StopCoroutine(autoEventCoroutine);
}
}
sealed class ConvoyController : FacepunchBehaviour {
internal ConvoySetting convoySetting;
internal List<ConvoyVehicle> convoyVehicles = new List<ConvoyVehicle>();
internal HashSet<ConvoyTruck> trucks = new HashSet<ConvoyTruck>();
internal List<ScientistNPC> roamNpc = new List<ScientistNPC>();
HashSet<ulong> lootedCrates = new HashSet<ulong>();
internal ConvoyHeli convoyHeli;
HashSet<ulong> convoyAttackersIds = new HashSet<ulong>();
ConvoyPath convoyPath;
ConvoyMarker convoyMarker;
Coroutine stopCoroutine;
Coroutine eventCoroutine;
int eventTime;
int stopTime;
#region API
internal bool CanConvoyEntityTakeDamage(HitInfo info, BaseEntity entity) {
if (info.Initiator != null && info.Initiator is AutoTurret) return true;
if (!info.InitiatorPlayer.IsRealPlayer()) return false;
if (!ins.PveModeAllowAction(info.InitiatorPlayer)) return false;
if (entity is PatrolHelicopter) {
if (Vector3.Distance(info.InitiatorPlayer.transform.position, entity.transform.position) >= ins._config.maxDamageDistance * 2) {
NotifyManager.SendMessageToPlayer(info.InitiatorPlayer, "Distance", info.InitiatorPlayer.UserIDString, ins._config.prefix);
return false;
}
}
else if (Vector3.Distance(info.InitiatorPlayer.transform.position, entity.transform.position) >= ins._config.maxDamageDistance) {
NotifyManager.SendMessageToPlayer(info.InitiatorPlayer, "Distance", info.InitiatorPlayer.UserIDString, ins._config.prefix);
return false;
}
return true;
}
internal bool CanConvoyNpcTakeDamage(HitInfo info) {
if (info.ProjectileDistance >= ins._config.maxDamageDistance) {
NotifyManager.SendMessageToPlayer(info.InitiatorPlayer, "Distance", info.InitiatorPlayer.UserIDString, ins._config.prefix);
return false;
}
return true;
}
internal void OnConvoyVehicleDie(ConvoyVehicle convoyVehicle) {
DefineFollow(convoyVehicle);
if (!ConvoyHaveAnySecurityVehivcle()) {
OnConvoyAttacked();
NotifyManager.SendMessageToAll("VehiclesKill", ins._config.prefix);
}
convoyVehicles.Remove(convoyVehicle);
}
internal ConvoyVehicle GetConvoyVehicleByEntityNetId(ulong netID) {
return convoyVehicles.FirstOrDefault(x => x != null && x.baseEntity != null && x.baseEntity.net.ID.Value == netID);
}
internal ConvoyTruck GetTruckByCrateNetID(ulong crateNetID) {
return trucks.FirstOrDefault(x => x != null && x.IsOwnCrate(crateNetID));
}
internal Vector3 GetConvoyPosition() {
if (convoyVehicles == null || convoyVehicles.Count == 0) return Vector3.zero;
ConvoyVehicle frontVehicle = convoyVehicles.FirstOrDefault(x => x != null && x.baseEntity != null);
ConvoyVehicle lastVehicle = convoyVehicles.Last();
if (frontVehicle != null && lastVehicle != null && lastVehicle.baseEntity != null) return (frontVehicle.baseEntity.transform.position + lastVehicle.baseEntity.transform.position) / 2;
else if (frontVehicle != null) return frontVehicle.baseEntity.transform.position;
return Vector3.zero;
}
internal bool ConvoyHaveAnySecurityVehivcle() {
return convoyVehicles.Any(x => x != null && x.baseEntity != null && x is ConvoyTruck == false);
}
internal bool IsAnyCrateHacking() {
return trucks.Any(x => x != null && x.IsCrateHacking());
}
internal bool IsConvoyHeli(ulong heliNetId) {
return convoyHeli != n
// ... [Code preview truncated due to length. Full source in attached file] ...