C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
using Time = UnityEngine.Time;
namespace Oxide.Plugins {
[Info("RocketTurrets", "k1lly0u", "2.1.1")]
[Description("Allow users to covert auto turrets to fire rockets")]
class RocketTurrets : RustPlugin {
#region Fields
private StoredData storedData;
private DynamicConfigFile data;
[PluginReference]
Plugin Clans, Friends;
private QueueUpdater queueUpdater;
private static Permission Permission;
private bool hasLoaded;
private static bool isUnloading;
private static bool isCallingTargetHook;
private const string ROCKET_BASIC_ITEM = "ammo.rocket.basic";
private const string ROCKET_HV_ITEM = "ammo.rocket.hv";
private const string ROCKET_FIRE_ITEM = "ammo.rocket.fire";
private const string ROCKET_LAUNCHER_ITEM = "rocket.launcher";
private const string CAMERA_ITEM = "cctv.camera";
private const string COMPUTER_ITEM = "targeting.computer";
private const string ROCKET_BASIC_PREFAB = "assets/prefabs/ammo/rocket/rocket_basic.prefab";
private const string ROCKET_HV_PREFAB = "assets/prefabs/ammo/rocket/rocket_hv.prefab";
private const string ROCKET_FIRE_PREFAB = "assets/prefabs/ammo/rocket/rocket_fire.prefab";
private const string FIREBALL_PREFAB = "assets/bundled/prefabs/oilfireballsmall.prefab";
private const string ROCKET_FIRE_EFFECT = "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab";
private const string WEAPON_SOCKET_BONE = "WeaponAttachmentPoint";
private const string BASIC_PERMISSION = "rocketturrets.rocket";
private const string AA_PERMISSION = "rocketturrets.antiair";
private const string JAVELIN_PERMISSION = "rocketturrets.javelin";
private const string NOLIMIT_PERMISSION = "rocketturrets.unlimited";
private const string NOAMMO_PERMISSION = "rocketturrets.unlimitedammo";
private static List<PatrolHelicopter> _patrolHelicopters = new List<PatrolHelicopter>();
#endregion
#region Oxide Hooks
private void Loaded() {
isUnloading = false;
Permission = permission;
lang.RegisterMessages(Messages, this);
permission.RegisterPermission(BASIC_PERMISSION, this);
permission.RegisterPermission(AA_PERMISSION, this);
permission.RegisterPermission(JAVELIN_PERMISSION, this);
permission.RegisterPermission(NOAMMO_PERMISSION, this);
permission.RegisterPermission(NOLIMIT_PERMISSION, this);
foreach (string key in configData.VIPLimits.Keys) permission.RegisterPermission(key, this);
data = Interface.Oxide.DataFileSystem.GetFile("rocketturrets_data");
//Physics.IgnoreLayerCollision(18, 13, false);
LoadData();
}
private void OnServerInitialized() {
_patrolHelicopters.Clear();
IEnumerable<BaseNetworkable> helicopters = BaseNetworkable.serverEntities.Where(x => x is PatrolHelicopter);
foreach (BaseNetworkable baseNetworkable in helicopters) {
if (baseNetworkable is PatrolHelicopter helicopter) _patrolHelicopters.Add(helicopter);
}
timer.In(3f, RestoreTurrets);
}
private void OnNewSave(string str) => storedData.launchers.Clear();
private void OnServerSave() {
if (!Interface.Oxide.IsShuttingDown) {
if (hasLoaded) {
for (int i = RocketTurret.allTurrets.Count - 1; i >= 0; i--) RocketTurret.allTurrets[i]?.PrepareForGameSave();
SaveRestore.Instance.StartCoroutine(RestoreOnSaveFinished());
}
}
SaveData();
}
private void OnEntitySpawned(PatrolHelicopter helicopter) {
if (!helicopter || _patrolHelicopters.Contains(helicopter)) return;
_patrolHelicopters.Add(helicopter);
}
private void OnEntityKill(PatrolHelicopter helicopter) {
if (!helicopter || !_patrolHelicopters.Contains(helicopter)) return;
_patrolHelicopters.Remove(helicopter);
}
private IEnumerator RestoreOnSaveFinished() {
while (SaveRestore.IsSaving) yield return null;
yield return CoroutineEx.waitForEndOfFrame;
yield return CoroutineEx.waitForEndOfFrame;
for (int i = RocketTurret.allTurrets.Count - 1; i >= 0; i--) RocketTurret.allTurrets[i]?.RestoreAfterGameSave();
}
private void CanPickupEntity(AutoTurret turret, BasePlayer player) {
if (configData.Settings.ReturnOnPickup == 0) return;
RocketTurret rocketTurret = turret.GetComponent<RocketTurret>();
if (!rocketTurret) return;
ReturnResources(player, rocketTurret.type, configData.Settings.ReturnOnPickup);
UnityEngine.Object.Destroy(rocketTurret);
}
private object OnTurretTarget(AutoTurret turret, BaseCombatEntity baseCombatEntity) {
if (isCallingTargetHook || !turret || !baseCombatEntity) return null;
RocketTurret rocketTurret = turret.GetComponent<RocketTurret>();
if (!rocketTurret) return null;
if (Vector3.Distance(baseCombatEntity.transform.position, rocketTurret.transform.position) > rocketTurret.Config.MaxTargetingDistance) return true;
return null;
}
private static object CallTargetingHook(AutoTurret turret, BaseCombatEntity baseCombatEntity) {
isCallingTargetHook = true;
object obj = Interface.Call("OnTurretTarget", turret, baseCombatEntity);
isCallingTargetHook = false;
return obj;
}
private void Unload() {
if (queueUpdater) UnityEngine.Object.Destroy(queueUpdater.gameObject);
//Physics.IgnoreLayerCollision(18, 13, true);
SaveData();
isUnloading = true;
for (int i = RocketTurret.allTurrets.Count - 1; i >= 0; i--) UnityEngine.Object.Destroy(RocketTurret.allTurrets[i]);
RocketTurret.allTurrets.Clear();
RocketTurret[] rocketTurrets = UnityEngine.Object.FindObjectsOfType<RocketTurret>();
for (int i = 0; i < rocketTurrets.Length; i++) UnityEngine.Object.Destroy(rocketTurrets[i]);
Permission = null;
configData = null;
}
#endregion
#region Functions
private void RestoreTurrets() {
if (storedData.launchers.Count > 0) {
List<BaseNetworkable> entities = BaseNetworkable.serverEntities.Where(x => x is AutoTurret).ToList();
foreach (BaseNetworkable entity in entities) {
if (storedData.launchers.TryGetValue(entity.net.ID.Value, out StoredData.Turret t)) {
RocketTurret.Load(entity as AutoTurret, t);
}
}
}
queueUpdater = QueueUpdater.Create();
hasLoaded = true;
}
private bool ParseType<T>(string type, out T value) {
value = default(T);
try {
value = (T)Enum.Parse(typeof(T), type, true);
if (Enum.IsDefined(typeof(T), value)) return true;
}
catch {
return false;
}
return false;
}
private T FindEntityFromRay<T>(BasePlayer player) where T : Component {
if (!Physics.Raycast(player.eyes.HeadRay(), out RaycastHit hit, 3f)) return null;
return hit.collider?.GetComponentInParent<T>();
}
private int CountTurrets(ulong userId, TurretType type) {
int count = 0;
for (int i = 0; i < RocketTurret.allTurrets.Count; i++) {
RocketTurret rocketTurret = RocketTurret.allTurrets[i];
if (rocketTurret.Turret.OwnerID == userId && rocketTurret.type == type) count++;
}
return count;
}
private int CountTurretsForBuilding(AutoTurret autoTurret) {
BuildingManager.Building building = autoTurret.GetBuilding();
int count = 0;
foreach (DecayEntity decayEntity in building.decayEntities) {
if (!(decayEntity is AutoTurret)) continue;
if (decayEntity.GetComponent<RocketTurret>()) count++;
}
return count;
}
private static List<ConfigData.TurretConfig.ItemCost> GetTurretCosts(TurretType type) => type == TurretType.AA ? configData.AntiAir.Cost : type == TurretType.Basic ? configData.Basic.Cost : configData.Javelin.Cost;
private bool HasResources(BasePlayer player, TurretType type) {
List<ConfigData.TurretConfig.ItemCost> costs = GetTurretCosts(type);
for (int i = 0; i < costs.Count; i++) {
ConfigData.TurretConfig.ItemCost cost = costs[i];
if (player.inventory.GetAmount(ItemManager.itemDictionaryByName[cost.Shortname].itemid) < cost.Amount) return false;
}
return true;
}
private void TakeResources(BasePlayer player, TurretType type) {
List<ConfigData.TurretConfig.ItemCost> costs = GetTurretCosts(type);
for (int i = 0; i < costs.Count; i++) {
ConfigData.TurretConfig.ItemCost cost = costs[i];
player.inventory.Take(null, ItemManager.itemDictionaryByName[cost.Shortname].itemid, cost.Amount);
}
}
private void ReturnResources(BasePlayer player, TurretType type, float percentage) {
List<ConfigData.TurretConfig.ItemCost> costs = GetTurretCosts(type);
for (int i = 0; i < costs.Count; i++) {
ConfigData.TurretConfig.ItemCost cost = costs[i];
int amount = Mathf.RoundToInt(cost.Amount * (percentage / 100));
if (amount == 0) continue;
Item item = ItemManager.CreateByName(cost.Shortname, amount);
player.GiveItem(item, BaseEntity.GiveItemReason.PickedUp);
}
}
private static void DropResources(AutoTurret turret, TurretType type, float percentage) {
List<ConfigData.TurretConfig.ItemCost> costs = GetTurretCosts(type);
for (int i = 0; i < costs.Count; i++) {
ConfigData.TurretConfig.ItemCost cost = costs[i];
int amount = Mathf.CeilToInt(cost.Amount * (percentage / 100f));
if (amount == 0) continue;
if (cost.Shortname == ROCKET_LAUNCHER_ITEM) continue;
Vector3 random = Random.onUnitSphere;
random.y = Mathf.Abs(random.y);
Item item = ItemManager.CreateByName(cost.Shortname, amount);
item.Drop(turret.transform.position + Vector3.up, (Vector3.up + random) * 2f);
}
}
private int GetTurretLimit(string playerId, TurretType type) {
int count = -1;
foreach (KeyValuePair<string, Dictionary<TurretType, int>> kvp in configData.VIPLimits) {
if (permission.UserHasPermission(playerId, kvp.Key)) {
int amount = kvp.Value[type];
if (amount > count) count = amount;
}
}
if (count == -1) count = type == TurretType.Basic ? configData.Basic.MaxPerPlayer : type == TurretType.AA ? configData.AntiAir.MaxPerPlayer : configData.Javelin.MaxPerPlayer;
return count;
}
#endregion
#region API
private void TryFireRocket(AutoTurret turret) {
RocketTurret rocketTurret = turret.GetComponent<RocketTurret>();
if (rocketTurret) {
if (Time.time >= rocketTurret.nextShotTime && turret.targetVisible) {
if (rocketTurret.HasAmmo()) {
Vector3 muzzlePos = turret.eyePos.position + (turret.eyePos.rotation * Vector3.forward * 10f);
if (rocketTurret.FireStandardRocket(muzzlePos)) rocketTurret.OnRocketFired();
}
}
}
}
private bool IsRocketTurret(AutoTurret turret) => turret.GetComponent<RocketTurret>();
private void ToggleTurretAutomation(AutoTurret turret, bool isOn) {
RocketTurret rocketTurret = turret.GetComponent<RocketTurret>();
if (rocketTurret) turret.SetIsOnline(isOn);
}
#endregion
#region Components
private class QueueUpdater : MonoBehaviour {
internal static QueueUpdater Create() => new GameObject("RocketTurret.QueueUpdater").AddComponent<QueueUpdater>();
private void Update() {
RocketTurret.updateTurretScanQueue.RunQueue(0.5);
}
}
private class UpdateRocketTurretScanQueue : ObjectWorkQueue<RocketTurret> {
#if (OXIDE_PUBLICIZED)
public override void RunJob(RocketTurret turret)
#else
protected override void RunJob(RocketTurret turret)
#endif
{
if (!ShouldAdd(turret)) return;
turret.TargetScan();
}
#if (OXIDE_PUBLICIZED)
public override bool ShouldAdd(RocketTurret turret)
#else
protected override bool ShouldAdd(RocketTurret turret)
#endif
{
if (!base.ShouldAdd(turret)) return false;
return turret && turret.Turret && turret.Turret.IsValid();
}
}
#region Turrets
private class RocketTurret : MonoBehaviour {
internal static List<RocketTurret> allTurrets = new List<RocketTurret>();
internal static UpdateRocketTurretScanQueue updateTurretScanQueue;
static RocketTurret() {
updateTurretScanQueue = new UpdateRocketTurretScanQueue();
}
internal AutoTurret Turret {
get;
private set;
}
internal BaseLauncher BaseLauncher {
get;
private set;
}
internal Item LauncherItem {
get;
private set;
}
internal TurretType type;
internal Transform tr;
private List<BaseEntity> attachments;
private Item lastAmmoItem;
private float targetAcquiredTime;
internal float nextShotTime = Time.time;
private bool dropResources;
public float nextScanTime;
private RealTimeSinceEx timeSinceLastServerTick;
public virtual ConfigData.TurretConfig Config => configData.Basic;
public static void Load(AutoTurret autoTurret, StoredData.Turret storedTurret) {
if (autoTurret.GetComponent<RocketTurret>()) return;
switch (storedTurret.type) {
case TurretType.Basic : RocketTurret rocketTurret = autoTurret.gameObject.AddComponent<RocketTurret>();
Interface.Oxide.NextTick(() => rocketTurret.OnLoad(storedTurret));
break;
case TurretType.AA : AATurret aaTurret = autoTurret.gameObject.AddComponent<AATurret>();
Interface.Oxide.NextTick(() => aaTurret.OnLoad(storedTurret));
break;
case TurretType.Javelin : JavelinTurret javelinTurret = autoTurret.gameObject.AddComponent<JavelinTurret>();
Interface.Oxide.NextTick(() => javelinTurret.OnLoad(storedTurret));
break;
}
}
protected virtual void Awake() {
allTurrets.Add(this);
Turret = GetComponent<AutoTurret>();
type = TurretType.Basic;
tr = Turret.transform;
attachments = Pool.Get<List<BaseEntity>>();
BuildCosmetics();
Turret.CancelInvoke(Turret.ServerTick);
Turret.CancelInvoke(Turret.ScheduleForTargetScan);
AutoTurret.updateAutoTurretScanQueue.Remove(Turret);
InvokeHandler.InvokeRepeating(this, ServerTick, Random.Range(0f, 1f), 0.015f);
//5846
InvokeHandler.InvokeRandomized(this, ScheduleForTargetScan, Random.Range(0f, 1f), Turret.TargetScanRate(), 0.2f);
Turret.targetTrigger.GetComponent<SphereCollider>().radius = Config.MaxTargetingDistance;
Turret.SetTarget(null);
}
private void Start() {
AutoTurret.updateAutoTurretScanQueue.Remove(Turret);
}
protected virtual void OnDestroy() {
InvokeHandler.CancelInvoke(this, ServerTick);
InvokeHandler.CancelInvoke(this, ScheduleForTargetScan);
RemoveCosmetics();
if (Turret && !Turret.IsDestroyed) {
if (dropResources) DropResources(Turret, type, configData.Settings.ReturnOnRemove);
Turret.inventory.canAcceptItem -= CanAcceptItem;
Turret.inventory.onItemAddedRemoved -= OnItemAddedOrRemoved;
if (LauncherItem != null) {
LauncherItem.RemoveFromWorld();
LauncherItem.RemoveFromContainer();
LauncherItem.Remove();
}
Turret.inventory.onlyAllowedItems = null;
Turret.inventory.canAcceptItem += Turret.CanAcceptItem;
Turret.inventory.onItemAddedRemoved += Turret.OnItemAddedOrRemoved;
Turret.AttachedWeapon = null;
Turret.Invoke(Turret.UpdateAttachedWeapon, 0.5f);
if (Turret.IsOnline()) {
Turret.InvokeRepeating(Turret.ServerTick, Random.Range(0f, 1f), 0.015f);
Turret.InvokeRandomized(Turret.ScheduleForTargetScan, Random.Range(0f, 1f), Turret.TargetScanRate(), 0.2f);
}
Turret.targetTrigger.GetComponent<SphereCollider>().radius = Turret.sightRange;
}
Pool.FreeUnmanaged(ref attachments);
allTurrets.Remove(this);
}
public void OnLoad(StoredData.Turret storedTurret) {
if (!BaseLauncher) {
Debug.LogError("No launcher");
return;
}
if (!string.IsNullOrEmpty(storedTurret.loadedAmmo) && BaseLauncher.primaryMagazine.ammoType.shortname != storedTurret.loadedAmmo) BaseLauncher.primaryMagazine.ammoType = ItemManager.FindItemDefinition(storedTurret.loadedAmmo);
BaseLauncher.primaryMagazine.contents = storedTurret.loadedCapacity;
}
#region Save Hack
public void PrepareForGameSave() {
if (LauncherItem != null) LauncherItem.removeTime = 1f;
}
public void RestoreAfterGameSave() {
if (LauncherItem != null) LauncherItem.removeTime = 0f;
}
#endregion
#region Cosmetics
protected virtual void BuildCosmetics() {
Item currentWeapon = Turret.inventory.GetSlot(0);
bool hasLauncher = false;
if (currentWeapon != null) {
if (currentWeapon.info.shortname != ROCKET_LAUNCHER_ITEM) {
currentWeapon.RemoveFromContainer();
currentWeapon.Drop(Turret.transform.position + Vector3.up, Vector3.up * 3f);
}
else {
BaseLauncher = currentWeapon.GetHeldEntity() as BaseLauncher;
hasLauncher = true;
}
}
Turret.inventory.canAcceptItem -= Turret.CanAcceptItem;
Turret.inventory.canAcceptItem += CanAcceptItem;
Turret.inventory.onItemAddedRemoved -= Turret.OnItemAddedOrRemoved;
Turret.inventory.onItemAddedRemoved += OnItemAddedOrRemoved;
List<ItemDefinition> allowedRockets = Pool.Get<List<ItemDefinition>>();
if (Config.AllowedRockets.Contains(ROCKET_BASIC_ITEM)) allowedRockets.Add(BasicRocketDefinition);
if (Config.AllowedRockets.Contains(ROCKET_FIRE_ITEM)) allowedRockets.Add(IncendiaryRocketDefinition);
if (Config.AllowedRockets.Contains(ROCKET_HV_ITEM)) allowedRockets.Add(HvRocketDefinition);
Turret.inventory.onlyAllowedItems = allowedRockets.ToArray();
Pool.FreeUnmanaged(ref allowedRockets);
if (!hasLauncher) {
LauncherItem = ItemManager.CreateByName(ROCKET_LAUNCHER_ITEM, 1, Config.LauncherSkin);
MoveItemToInventory(LauncherItem);
BaseLauncher = LauncherItem.GetHeldEntity() as BaseLauncher;
}
else {
LauncherItem = currentWeapon;
if (!Turret.IsInvoking(UpdateAttachedWeapon)) Turret.Invoke(UpdateAttachedWeapon, 0.5f);
}
AttachToTurret(ItemManager.CreateByName(ROCKET_BASIC_ITEM), new Vector3(0.2f, 0f, -0.1f), new Vector3(0, 90, 0));
AttachToTurret(ItemManager.CreateByName(ROCKET_BASIC_ITEM), new Vector3(-0.2f, 0f, -0.1f), new Vector3(0, 90, 0));
}
protected void AttachToTurret(Item item, Vector3 localPosition, Vector3 localEuler, string bone = WEAPON_SOCKET_BONE) {
BaseEntity worldEntity = GameManager.server.CreateEntity("assets/prefabs/misc/burlap sack/generic_world.prefab", tr.position, tr.rotation);
WorldItem worldItem = worldEntity as WorldItem;
worldItem.InitializeItem(item);
worldItem.allowPickup = false;
worldEntity.enableSaving = false;
worldEntity.Spawn();
worldItem.CancelInvoke((worldItem as DroppedItem).IdleDestroy);
item.SetWorldEntity(worldEntity);
Rigidbody rb = worldEntity.GetComponent<Rigidbody>();
rb.isKinematic = true;
rb.useGravity = false;
worldEntity.SetParent(Turret, bone);
worldEntity.transform.localPosition = localPosition;
worldEntity.transform.localRotation = Quaternion.Euler(localEuler);
attachments.Add(worldEntity);
}
private void RemoveCosmetics() {
for (int i = 0; i < attachments?.Count; i++) {
BaseEntity worldEntity = attachments[i];
if (worldEntity && !worldEntity.IsDestroyed) {
(worldEntity as WorldItem).DestroyItem();
worldEntity.Kill();
}
}
}
#endregion
#region Item Management
private void MoveItemToInventory(Item item) {
item.RemoveFromContainer();
item.RemoveFromWorld();
item.position = 0;
item.SetParent(Turret.inventory);
Turret.inventory.MarkDirty();
item.MarkDirty();
if (!Turret.IsInvoking(UpdateAttachedWeapon)) Turret.Invoke(UpdateAttachedWeapon, 0.5f);
}
private void OnItemAddedOrRemoved(Item item, bool added) {
if (isUnloading) return;
if (!added && item != null && item.info.shortname == ROCKET_LAUNCHER_ITEM) {
dropResources = true;
Destroy(this, 0.5f);
}
}
private bool CanAcceptItem(Item item, int targetSlot) {
Item slot = Turret.inventory.GetSlot(0);
if (item.info.shortname == ROCKET_LAUNCHER_ITEM && targetSlot == 0) return true;
if (item.info.category != ItemCategory.Ammunition || slot == null || !Turret.GetAttachedWeapon() || targetSlot == 0) return false;
return true;
}
private void UpdateAttachedWeapon() {
Item slot = Turret.inventory.GetSlot(0);
BaseLauncher baseLauncher = null;
if (slot != null && slot.info.category == ItemCategory.Weapon) {
BaseEntity heldEntity = slot.GetHeldEntity();
if (heldEntity) {
baseLauncher = heldEntity.GetComponent<BaseLauncher>();
}
}
Turret.SetFlag(BaseEntity.Flags.Reserved3, baseLauncher);
if (!baseLauncher) {
if (Turret.AttachedWeapon) {
Turret.AttachedWeapon.SetGenericVisible(false);
Turret.AttachedWeapon.SetLightsOn(false);
}
Turret.AttachedWeapon = null;
return;
}
baseLauncher.SetLightsOn(true);
baseLauncher.limitNetworking = false;
baseLauncher.SetFlag(BaseEntity.Flags.Disabled, false);
baseLauncher.SetParent(Turret, WEAPON_SOCKET_BONE);
baseLauncher.transform.localPosition = new Vector3(-0.15f, 0.1f, 0f);
baseLauncher.transform.localRotation = Quaternion.Euler(180f, 95f, -52f);
baseLauncher.SetGenericVisible(true);
BaseLauncher = baseLauncher;
Turret.AttachedWeapon = baseLauncher;
Turret.totalAmmoDirty = true;
Turret.Reload();
Turret.UpdateTotalAmmo();
baseLauncher.SendNetworkUpdateImmediate();
Turret.SendNetworkUpdateImmediate();
}
#endregion
#region Think
private void ServerTick() {
if (!Turret || Turret.IsDestroyed) return;
float timeSince = (float) timeSinceLastServerTick;
timeSinceLastServerTick = 0;
if (!Turret.IsOnline()) Turret.OfflineTick();
else if (!Turret.HasTarget()) Turret.IdleTick(timeSince);
else TargetTick();
Turret.UpdateFacingToTarget(timeSince);
if (Turret.totalAmmoDirty && Time.time > Turret.nextAmmoCheckTime) {
Turret.UpdateTotalAmmo();
Turret.totalAmmoDirty = false;
Turret.nextAmmoCheckTime = Time.time + 0.5f;
}
}
private void ScheduleForTargetScan() {
updateTurretScanQueue.Add(this);
}
internal virtual void TargetScan() {
if (Turret.IsOffline()) return;
Vector3 muzzlePos = Turret.eyePos.position + (Turret.eyePos.rotation * Vector3.forward * 0.5f);
if (Turret.HasTarget()) {
if (Vector3.Distance(muzzlePos, Turret.target.transform.position) < Config.MinTargetingDistance || ShouldForgetTarget(Turret.target)) Turret.SetTarget(null);
return;
}
if (Turret.targetTrigger.entityContents != null) {
foreach (BaseEntity baseEntity in Turret.targetTrigger.entityContents) {
if (!baseEntity) continue;
BaseCombatEntity component = baseEntity as BaseCombatEntity;
if (!component || !component.IsAlive() || !Turret.InFiringArc(component) || !Turret.ObjectVisible(component)) continue;
if (!CanTargetEntity(component)) continue;
if (Vector3.Distance(muzzlePos, component.transform.position) < Config.MinTargetingDistance) continue;
if (Turret.PeacekeeperMode()) {
if (!Turret.IsEntityHostile(component)) {
continue;
}
if (!Turret.target) {
nextShotTime = Time.time + 1f;
}
}
SetTarget(component);
break;
}
}
}
protected virtual bool ShouldForgetTarget(BaseCombatEntity baseCombatEntity) {
return false;
}
protected void SetTarget(BaseCombatEntity component) {
if (component != Turret.target) targetAcquiredTime = Time.realtimeSinceStartup;
isCallingTargetHook = true;
Turret.SetTarget(component);
isCallingTargetHook = false;
}
protected virtual bool CanTargetEntity(BaseCombatEntity component) {
// if (component is AutoTurret or RidableHorse2)
return false;
BasePlayer player = component as BasePlayer;
if (player) {
if (!Config.TargetNPCs && player.IsNpc) return false;
if (Turret.IsAuthed(player)) return false;
}
BaseVehicle vehicle = component as BaseVehicle;
if (vehicle && vehicle.mountPoints != null) {
foreach (BaseVehicle.MountPointInfo vehicleMountPoint in vehicle.mountPoints) {
if (vehicleMountPoint == null || !vehicleMountPoint.mountable) continue;
player = vehicleMountPoint.mountable.GetMounted();
if (player && Turret.IsAuthed(player)) return false;
}
}
object obj = CallTargetingHook(Turret, component);
if (obj is bool b) return b;
return true;
}
private void TargetTick() {
if (Time.realtimeSinceStartup >= Turret.nextVisCheck) {
Turret.nextVisCheck = Time.realtimeSinceStartup + Random.Range(0.2f, 0.3f);
Turret.targetVisible = Turret.ObjectVisible(Turret.target);
if (Turret.targetVisible) {
Turret.lastTargetSeenTime = Time.realtimeSinceStartup;
}
}
if (Time.time >= nextShotTime && Turret.targetVisible) {
if (!HasAmmo()) nextShotTime = Time.time + Config.FireRate;
else {
if (Time.realtimeSinceStartup < targetAcquiredTime + Config.LockDuration) return;
if (FireRocket(Turret.target.transform.position, Turret.target)) OnRocketFired();
}
}
if (Turret.target.IsDead() || Time.realtimeSinceStartup - Turret.lastTargetSeenTime > 3f || Vector3.Distance(transform.position, Turret.target.transform.position) > Turret.sightRange || (Turret.PeacekeeperMode() && !Turret.IsEntityHostile(Turret.target))) {
SetTarget(null);
}
}
internal bool HasAmmo() {
if (!Config.RequiresAmmo || Permission.UserHasPermission(Turret.OwnerID.ToString(), NOAMMO_PERMISSION)) return true;
if (lastAmmoItem == null || lastAmmoItem.amount == 0) {
for (int i = 0; i < Turret.inventory.itemList.Count; i++) {
Item item = Turret.inventory.itemList[i];
if (item.info.shortname is ROCKET_BASIC_ITEM or ROCKET_FIRE_ITEM or ROCKET_HV_ITEM && item.amount > 0) {
BaseLauncher.primaryMagazine.ammoType = item.info;
lastAmmoItem = item;
return true;
}
}
return false;
}
return true;
}
#endregion
#region Shoot
protected virtual bool FireRocket(Vector3 targetPos, BaseCombatEntity target = null) {
if (Turret.IsOffline()) return false;
Vector3 muzzlePos = Turret.eyePos.position + (Turret.eyePos.rotation * Vector3.forward * 0.5f);
BaseEntity rocket = GameManager.server.CreateEntity(GetPrefabFromItem(), muzzlePos, Quaternion.Euler(targetPos - muzzlePos));
rocket.enableSaving = false;
rocket.Spawn();
Effect.server.Run(ROCKET_FIRE_EFFECT, rocket.transform.position);
if (Config.RocketTrail) AttachFireball(rocket);
rocket.creatorEntity = (BasePlayer.FindAwakeOrSleeping(Turret.OwnerID.ToString()) as BaseEntity) ?? Turret;
ConfigData.BasicTurret config = Config as ConfigData.BasicTurret;
if (config.SeekTarget) {
HeatSeekerRocket heatSeeker = rocket.gameObject.AddComponent<HeatSeekerRocket>();
heatSeeker.Initialize(target, targetPos, config.RocketSpeed, true, config.ProximityDetonation, config.DamageMultiplier);
}
else {
StandardRocket standardRocket = rocket.gameObject.AddComponent<StandardRocket>();
standardRocket.Initialize(target, targetPos, config.RocketSpeed, false, config.ProximityDetonation, config.DamageMultiplier);
}
return true;
}
protected void AttachFireball(BaseEntity parent) {
FireBall fireball = GameManager.server.CreateEntity(FIREBALL_PREFAB, parent.transform.position) as FireBall;
fireball.enableSaving = false;
fireball.Spawn();
Rigidbody rb = fireball.GetComponent<Rigidbody>();
rb.useGravity = false;
rb.isKinematic = true;
fireball.SetParent(parent);
fireball.transform.localPosition = Vector3.zero;
}
internal bool FireStandardRocket(Vector3 targetPos) {
if (Turret.IsOffline()) return false;
Vector3 muzzlePos = Turret.eyePos.position + (Turret.eyePos.rotation * Vector3.forward * 0.5f);
BaseEntity rocket = GameManager.server.CreateEntity(GetPrefabFromItem(), muzzlePos, Quaternion.Euler(targetPos - muzzlePos));
rocket.enableSaving = false;
rocket.Spawn();
Effect.server.Run(ROCKET_FIRE_EFFECT, rocket.transform.position);
rocket.creatorEntity = (BasePlayer.FindAwakeOrSleeping(Turret.OwnerID.ToString()) as BaseEntity) ?? Turret;
StandardRocket standardRocket = rocket.gameObject.AddComponent<StandardRocket>();
standardRocket.Initialize(null, targetPos, Config.RocketSpeed, false, false, Config.DamageMultiplier);
return true;
}
internal void OnRocketFired() {
nextShotTime = Time.time + Config.FireRate;
if (lastAmmoItem != null) {
lastAmmoItem.UseItem();
if (lastAmmoItem.amount <= 0) {
lastAmmoItem.RemoveFromContainer();
lastAmmoItem.Remove();
lastAmmoItem = null;
}
}
Turret.totalAmmoDirty = true;
}
protected string GetPrefabFromItem() {
if (lastAmmoItem == null) return ROCKET_BASIC_PREFAB;
switch (lastAmmoItem.info.shortname) {
case ROCKET_FIRE_ITEM : return ROCKET_FIRE_PREFAB;
case ROCKET_HV_ITEM : return ROCKET_HV_PREFAB;
case ROCKET_BASIC_ITEM : default : return ROCKET_BASIC_PREFAB;
}
}
#endregion
#region Definitions
private static ItemDefinition _basicRocketDefinition;
private static ItemDefinition _incendiaryRocketDefinition;
private static ItemDefinition _hvRocketDefinition;
private static ItemDefinition BasicRocketDefinition {
get {
if (!_basicRocketDefinition) _basicRocketDefinition = ItemManager.FindItemDefinition(ROCKET_BASIC_ITEM);
return _basicRocketDefinition;
}
}
private static ItemDefinition IncendiaryRocketDefinition {
get {
if (!_incendiaryRocketDefinition) _incendiaryRocketDefinition = ItemManager.FindItemDefinition(ROCKET_FIRE_ITEM);
return _incendiaryRocketDefinition;
}
}
private static ItemDefinition HvRocketDefinition {
get {
if (!_hvRocketDefinition) _hvRocketDefinition = ItemManager.FindItemDefinition(ROCKET_HV_ITEM);
return _hvRocketDefinition;
}
}
#endregion
}
private class AATurret : RocketTurret {
public override ConfigData.TurretConfig Config => configData.AntiAir;
private ConfigData.AntiAirTurret AAConfig => Config as ConfigData.AntiAirTurret;
private readonly List<BaseEntity> _potentialTargets = new List<BaseEntity>();
private float _nextScanTime;
protected override void Awake() {
base.Awake();
type = TurretType.AA;
}
protected override void BuildCosmetics() {
base.BuildCosmetics();
AttachToTurret(ItemManager.CreateByName(COMPUTER_ITEM), new Vector3(0f, 0f, -0.52f), Vector3.zero, string.Empty);
AttachToTurret(ItemManager.CreateByName(CAMERA_ITEM), new Vector3(0.2f, 0.1f, -0.1f), new Vector3(0, 90f, 0f));
AttachToTurret(ItemManager.CreateByName(CAMERA_ITEM), new Vector3(-0.2f, 0.1f, -0.1f), new Vector3(0, 90f, 0f));
}
internal override void TargetScan() {
if (Turret.IsOffline()) return;
if (Turret.HasTarget()) {
Vector3 muzzlePos = Turret.eyePos.position + (Turret.eyePos.rotation * Vector3.forward * 0.5f);
if (Vector3.Distance(muzzlePos, Turret.target.transform.position) < Config.MinTargetingDistance || ShouldForgetTarget(Turret.target)) Turret.SetTarget(null);
return;
}
if (Time.time > _nextScanTime) {
_nextScanTime = Time.time + Random.Range(2.8f, 3.2f);
_potentialTargets.Clear();
_potentialTargets.AddRange(_patrolHelicopters);
if (Turret.targetTrigger.entityContents != null) _potentialTargets.AddRange(Turret.targetTrigger.entityContents);
AddTargetSet(_potentialTargets);
}
foreach (BaseEntity baseEntity in _potentialTargets) {
if (baseEntity is not BaseCombatEntity component || !component || component.IsDestroyed || !component.IsAlive()) continue;
if (component.transform.position.y < tr.position.y) continue;
float distance = Vector3.Distance(component.transform.position, transform.position);
if (distance < Config.MinTargetingDistance || distance > Config.MaxTargetingDistance) continue;
if (!Turret.InFiringArc(component) || !Turret.ObjectVisible(component)) continue;
if (!CanTargetEntity(component)) continue;
if (Turret.PeacekeeperMode()) {
if (!Turret.IsEntityHostile(component)) {
continue;
}
if (!Turret.target) {
nextShotTime = Time.time + 1f;
}
}
SetTarget(component);
break;
}
}
private void AddTargetSet(List<BaseEntity> allTargets) {
foreach (SamSite.ISamSiteTarget samSiteTarget in SamSite.ISamSiteTarget.serverList) {
Vector3 position = samSiteTarget.CenterPoint();
if (samSiteTarget is MLRSRocket or not BaseCombatEntity) continue;
float distance = Vector3.Distance(position, transform.position);
if (distance < Config.MinTargetingDistance || distance > Config.MaxTargetingDistance) continue;
allTargets.Add(samSiteTarget as BaseCombatEntity);
}
}
protected override bool CanTargetEntity(BaseCombatEntity component) {
// if (component.transform.position.y < tr.position.y || component is AutoTurret || component is RidableHorse2)
return false;
if (component is PatrolHelicopter) return AAConfig.Patrol;
if (component is BaseHelicopter entity) {
if (entity is CH47Helicopter) return AAConfig.CH47;
if (!AAConfig.Helicopters) return false;
bool hasMounted = false;
for (int i = 0; i < entity.mountPoints?.Count; i++) {
BaseMountable mountable = entity.mountPoints[i].mountable;
if (mountable.AnyMounted()) {
hasMounted = true;
BasePlayer basePlayer = mountable.GetMounted();
if (basePlayer) {
if (Turret.IsAuthed(basePlayer)) return false;
object obj = CallTargetingHook(Turret, basePlayer);
if (obj is bool b) return b;
}
}
}
return hasMounted;
}
if (component is HotAirBalloon hotAirBalloon && AAConfig.HAB) {
bool hasMounted = false;
for (int i = 0; i < hotAirBalloon.children?.Count; i++) {
BasePlayer basePlayer = hotAirBalloon.children[i] as BasePlayer;
if (basePlayer) {
hasMounted = true;
if (Turret.IsAuthed(basePlayer)) return false;
object obj = CallTargetingHook(Turret, basePlayer);
if (obj is bool b) return b;
}
}
return hasMounted;
}
if (component is BasePlayer {
isMounted : true
}
player) {
BaseVehicle baseVehicle = player.GetMounted().GetComponentInParent<BaseVehicle>();
if (!baseVehicle) return false;
for (int i = 0; i < baseVehicle?.mountPoints?.Count; i++) {
BaseMountable mountable = baseVehicle.mountPoints[i].mountable;
if (mountable.AnyMounted()) {
BasePlayer basePlayer = mountable.GetMounted();
if (basePlayer != null) {
if (Turret.IsAuthed(basePlayer)) return false;
object obj = CallTargetingHook(Turret, basePlayer);
if (obj is bool b) return b;
}
}
}
if (Turret.IsAuthed(player)) return false;
object obj1 = CallTargetingHook(Turret, player);
if (obj1 is bool obj2) return obj2;
return true;
}
return false;
}
protected override bool ShouldForgetTarget(BaseCombatEntity baseCombatEntity) {
return baseCombatEntity.transform.position.y < tr.position.y;
}
protected override bool FireRocket(Vector3 targetPos, BaseCombatEntity target = null) {
if (Turret.IsOffline()) return false;
Vector3 muzzlePos = Turret.eyePos.position + (Turret.eyePos.rotation * Vector3.forward * 0.5f);
BaseEntity rocket = GameManager.server.CreateEntity(GetPrefabFromItem(), muzzlePos, Quaternion.Euler(targetPos - muzzlePos));
rocket.enableSaving = false;
rocket.Spawn();
Effect.server.Run(ROCKET_FIRE_EFFECT, rocket.transform.position);
if (AAConfig.RocketTrail) AttachFireball(rocket);
rocket.creatorEntity = (BasePlayer.FindAwakeOrSleeping(Turret.OwnerID.ToString()) as BaseEntity) ?? Turret;
ConfigData.AntiAirTurret config = AAConfig;
HeatSeekerRocket heatSeeker = rocket.gameObject.AddComponent<HeatSeekerRocket>();
heatSeeker.Initialize(target, targetPos, config.RocketSpeed, true, true, config.DamageMultiplier);
return true;
}
}
private class JavelinTurret : RocketTurret {
public override ConfigData.TurretConfig Config => configData.Javelin;
protected override void Awake() {
base.Awake();
type = TurretType.Javelin;
}
protected override void BuildCosmetics() {
base.BuildCosmetics();
AttachToTurret(ItemManager.CreateByName(COMPUTER_ITEM), new Vector3(0f, 0, -0.52f), Vector3.zero, string.Empty);
}
protected override bool FireRocket(Vector3 targetPos, BaseCombatEntity target = null) {
if (Turret.IsOffline()) return false;
Vector3 muzzlePos = Turret.eyePos.position + (Turret.eyePos.rotation * Vector3.forward * 0.5f);
BaseEntity rocket = GameManager.server.CreateEntity(GetPrefabFromItem(), muzzlePos, Quaternion.Euler(targetPos - muzzlePos));
rocket.enableSaving = false;
rocket.Spawn();
Effect.server.Run(ROCKET_FIRE_EFFECT, rocket.transform.position);
if (Config.RocketTrail) AttachFireball(rocket);
rocket.creatorEntity = (BasePlayer.FindAwakeOrSleeping(Turret.OwnerID.ToString()) as BaseEntity) ?? Turret;
ConfigData.BasicTurret config = Config as ConfigData.BasicTurret;
JavelinRocket javelinRocket = rocket.gameObject.AddComponent<JavelinRocket>();
javelinRocket.Initialize(target, targetPos, config.RocketSpeed, config.SeekTarget, config.ProximityDetonation, config.DamageMultiplier);
return true;
}
}
#endregion
#region Rockets
private class StandardRocket : MonoBehaviour {
protected ServerProjectile projectile;
// ... [Code preview truncated due to length. Full source in attached file] ...